Fires in NYC and FDNY Response

Overview

For this assignment, we are going to investigate fires requiring the fire department to respond. Using data about the locations of firehouses and fires occurring in New York City, we want to know whether response times to fires differ across the city. Second, we will try to focus on one possible variable that could affect response times – the distance from the firehouse – and see whether we find the (expected) effect.

To keep this homework manageable, I am leaving out another part of the investigation: What is the effect of demographic and/or income characteristics of the neighborhood on response times. This is likely a bit more sensitive but also relevant from a public policy perspective.

Data

We rely on two data sets.

Incidents responded to by fire companies

NYC Open Data has data on all incidents responded to by fire companies. I have included the variable description file in the exercise folder. The following variables are available:

  • IM_INCIDENT_KEY: Unique identifier for each incident which serves
  • INCIDENT_TYPE_DESC The code and description of the incident category type
  • INCIDENT_DATE_TIME The date and time that the incident was logged into the Computer Aided Dispatch system
  • ARRIVAL_DATE_TIME The date and time that the first unit arrived on scene
  • UNITS_ONSCENE Total number of units that arrived on scene
  • LAST_UNIT_CLEARED_DATETIME The date and time that the incident was completed and the last unit cleared the scene
  • HIGHEST_LEVEL_DESC The highest alarm level that the incident received
  • TOTAL_INCIDENT_DURATION The total number of seconds from when then incident was created to when the incident was closed
  • ACTION_TAKEN1_DESC The code and description of the first action taken
  • ACTION_TAKEN2_DESC The code and description of the second action taken
  • ACTION_TAKEN3_DESC The code and description of the third action taken
  • PROPERTY_USE_DESC The code and description of the type of street or building where the incident took place
  • STREET_HIGHWAY The name of the street where the incident_took place
  • ZIP_CODE The postal zip code where the incident took place
  • BOROUGH_DESC The borough where the incident took place
  • FLOOR The floor of the building where the incident took place
  • CO_DETECTOR_PRESENT_DESC Indicator for when a CO detector was present
  • FIRE_ORIGIN_BELOW_GRADE_FLAG Indicator for when the fire originated below grade
  • STORY_FIRE_ORIGIN_COUNT Story in which the fire originated
  • FIRE_SPREAD_DESC How far the fire spread from the object of origin
  • DETECTOR_PRESENCE_DESC Indicator for when a detector was present
  • AES_PRESENCE_DESC Indicator for when an Automatic Extinguishing System is present
  • STANDPIPE_SYS_PRESENT_FLAG Indicator for when a standpipe was present in the area of origin of a fire

This dataset is only updated annually, and thus far only data from 2013 to 2018 is contained. The full dataset is also somewhat too large for an exercise (2.5M rows), so I suggest to limit yourself to a subset. I have added a file containing the subset of of only building fires (INCIDENT_TYPE_DESC == "111 - Building fire") for 2013 to 2018 only which yields about 14,000 incidents.

Unfortunately, the addresses of the incidents were not geocoded yet. Ideally, I would like you to know how to do this but am mindful about the hour or so required to get this done. So, here is the code. The geocodes (as far as they were returned successfully) are part of the data (as variables lat and lon).

library(ggmap)
Loading required package: ggplot2
Registered S3 method overwritten by 'dplyr':
  method           from
  print.rowwise_df     
Google's Terms of Service: https://cloud.google.com/maps-platform/terms/.
Please cite ggmap if you use it! See citation("ggmap") for details.
library(tidyverse)
── Attaching packages ──────────────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
✓ tibble  2.1.3     ✓ purrr   0.3.3
✓ tidyr   1.0.2     ✓ dplyr   0.8.3
✓ readr   1.3.1     ✓ forcats 0.4.0
── Conflicts ─────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(dplyr)
# Open "building_fires" file
fire_building <- read_csv("data/building_fires.csv")
Parsed with column specification:
cols(
  .default = col_character(),
  IM_INCIDENT_KEY = col_double(),
  UNITS_ONSCENE = col_double(),
  TOTAL_INCIDENT_DURATION = col_double(),
  ZIP_CODE = col_double(),
  FIRE_ORIGIN_BELOW_GRADE_FLAG = col_double(),
  STORY_FIRE_ORIGIN_COUNT = col_double(),
  STANDPIPE_SYS_PRESENT_FLAG = col_double(),
  lon = col_double(),
  lat = col_double()
)
See spec(...) for full column specifications.

FDNY Firehouse Listing

NYC Open Data also provides data on the location of all 218 firehouses in NYC. Relevant for our analysis are the following variables: FacilityName, Borough, Latitude, Longitude

firehouses <- read_csv("data/FDNY_Firehouse_Listing.csv") %>%
  dplyr::filter(!is.na(Latitude))
Parsed with column specification:
cols(
  FacilityName = col_character(),
  FacilityAddress = col_character(),
  Borough = col_character(),
  Postcode = col_double(),
  Latitude = col_double(),
  Longitude = col_double(),
  `Community Board` = col_double(),
  `Community Council` = col_double(),
  `Census Tract` = col_double(),
  BIN = col_double(),
  BBL = col_double(),
  NTA = col_character()
)

Note: 5 entries contain missing information, including on the spatial coordinates. We can exclude these for the exercise.

Tasks

1. Location of Severe Fires

Provide a leaflet map of the highest severity fires (i.e. subset to the highest category in HIGHEST_LEVEL_DESC) contained in the file buiding_fires.csv. Ignore locations that fall outside the five boroughs of New York City. Provide at least three pieces of information on the incident in a popup.

# subset to the highest alarm 
unique(fire_building$HIGHEST_LEVEL_DESC)
 [1] "7 - Signal 7-5"                                    "2 - 2nd alarm"                                    
 [3] "1 - More than initial alarm, less than Signal 7-5" "3 - 3rd alarm"                                    
 [5] "5 - 5th alarm"                                     "4 - 4th alarm"                                    
 [7] NA                                                  "0 - Initial alarm"                                
 [9] "75 - All Hands Working"                            "22 - Second Alarm"                                
[11] "55 - Fifth Alarm"                                  "11 - First Alarm"                                 
[13] "33 - Third Alarm"                                  "44 - Fourth Alarm"                                
highest_alarm <- fire_building %>%
  filter(HIGHEST_LEVEL_DESC=="7 - Signal 7-5"| HIGHEST_LEVEL_DESC=="75 - All Hands Working")
unique(highest_alarm$HIGHEST_LEVEL_DESC)
[1] "7 - Signal 7-5"         "75 - All Hands Working"
head(highest_alarm)
library(leaflet)
Warning messages:
1: Unknown or uninitialised column: 'class'. 
2: Unknown or uninitialised column: 'class'. 
3: Unknown or uninitialised column: 'class'. 
4: Unknown or uninitialised column: 'class'. 
5: Unknown or uninitialised column: 'class'. 
6: Unknown or uninitialised column: 'class'. 
7: Unknown or uninitialised column: 'class'. 
8: Unknown or uninitialised column: 'class'. 
9: Unknown or uninitialised column: 'class'. 
library(stringr)
highest_alarm_map <- leaflet(highest_alarm, options = leafletOptions(minZoom = 5, dragging = TRUE))%>%
  addProviderTiles(provider = "Esri")%>%
  setView( lat= 40.712742, lng=-74.013382, zoom = 10 ) %>%
  addCircleMarkers(lng = ~lon,lat = ~lat, radius = 1, popup = ~paste0("Date: ",str_extract(INCIDENT_DATE_TIME, pattern = "[0-9]+/[0-9]+/[0-9]+"), "<br/>", "Address: ", address, "<br/>", "Spread: ", str_sub(FIRE_SPREAD_DESC, 5,-1)))
highest_alarm_map

library(htmlwidgets)
saveWidget(highest_alarm_map, file="highest_alarm_map.html")

2. Layers and Clusters

a) Color by Type of Property

Start with the previous map. Now, distinguish the markers of the fire locations by PROPERTY_USE_DESC, i.e. what kind of property was affected. If there are too many categories, collapse some categories. Choose an appropriate coloring scheme to map the locations by type of affected property. Add a legend informing the user about the color scheme. Also make sure that the information about the type of affected property is now contained in the popup information. Show this map.

unique(highest_alarm$PROPERTY_USE_DESC)
  [1] "579 - Motor vehicle or boat sales, services, repair"     
  [2] "429 - Multifamily dwelling"                              
  [3] "419 - 1 or 2 family dwelling"                            
  [4] "700 - Manufacturing, processing"                         
  [5] "161 - Restaurant or cafeteria"                           
  [6] "881 - Parking garage, (detached residential garage)"     
  [7] "564 - Laundry, dry cleaning"                             
  [8] "400 - Residential, other"                                
  [9] "559 - Recreational, hobby, home repair sales, pet store" 
 [10] "500 - Mercantile, business, other"                       
 [11] "549 - Specialty shop"                                    
 [12] "331 - Hospital - medical or psychiatric"                 
 [13] "131 - Church, mosque, synagogue, temple, chapel"         
 [14] "210 - Schools, non-adult, other"                         
 [15] "519 - Food and beverage sales, grocery store"            
 [16] "449 - Hotel/motel, commercial"                           
 [17] "173 - Bus station"                                       
 [18] "891 - Warehouse"                                         
 [19] "599 - Business office"                                   
 [20] "580 - General retail, other"                             
 [21] "311 - 24-hour care Nursing homes, 4 or more persons"     
 [22] "UUU - Undetermined"                                      
 [23] "888 - Fire station"                                      
 [24] "900 - Outside or special property, other"                
 [25] "965 - Vehicle parking area"                              
 [26] "100 - Assembly, other"                                   
 [27] "960 - Street, other"                                     
 [28] "332 - Hospices"                                          
 [29] "439 - Boarding/rooming house, residential hotels"        
 [30] "123 - Stadium, arena"                                    
 [31] "141 - Athletic/health club"                              
 [32] "931 - Open land or field"                                
 [33] "962 - Residential street, road or residential driveway"  
 [34] "899 - Residential or self-storage units"                 
 [35] "322 - Alcohol or substance abuse recovery center"        
 [36] "170 - Passenger terminal, other"                         
 [37] "557 - Personal service, including barber & beauty shops" 
 [38] "880 - Vehicle storage, other"                            
 [39] "460 - Dormitory-type residence, other"                   
 [40] "800 - Storage, other"                                    
 [41] "610 - Energy production plant, other"                    
 [42] "926 - Outbuilding, protective shelter"                   
 [43] "000 - Property Use, other"                               
 [44] "511 - Convenience store"                                 
 [45] "162 - Bar or nightclub"                                  
 [46] "539 - Household goods, sales, repairs"                   
 [47] "981 - Construction site"                                 
 [48] "180 - Studio/theater, other"                             
 [49] "183 - Movie theater"                                     
 [50] "459 - Residential board and care"                        
 [51] "241 - Adult education center, college classroom"         
 [52] "152 - Museum"                                            
 [53] "593 - Office:  veterinary or research"                   
 [54] "130 - Places of worship, funeral parlors, other"         
 [55] "160 - Eating, drinking places, other"                    
 [56] "300 - Health care, detention, & correction, other"       
 [57] "642 - Electrical distribution"                           
 [58] "963 - Street or road in commercial area"                 
 [59] "342 - Doctor, dentist or oral surgeon office"            
 [60] "529 - Textile, wearing apparel sales"                    
 [61] "321 - Mental retardation/development disability facility"
 [62] "340 - Clinics, doctors offices, hemodialysis cntr, other"
 [63] "882 - Parking garage, general vehicle"                   
 [64] "150 - Public or government, other"                       
 [65] "174 - Rapid transit station"                             
 [66] "648 - Sanitation utility"                                
 [67] "200 - Educational, other"                                
 [68] "596 - Post office or mailing firms"                      
 [69] "215 - High school/junior high school/middle school"      
 [70] "110 - Fixed-use recreation places, other"                
 [71] "592 - Bank"                                              
 [72] "365 - Police station"                                    
 [73] "571 - Service station, gas station"                      
 [74] "182 - Auditorium, concert hall"                          
 [75] "581 - Department or discount store"                      
 [76] "808 - Outbuilding or shed"                               
 [77] "839 - Refrigerated storage"                              
 [78] "121 - Ballroom, gymnasium"                               
 [79] "112 - Billiard center, pool hall"                        
 [80] "NNN - None"                                              
 [81] "142 - Clubhouse"                                         
 [82] "140 - Clubs, other"                                      
 [83] "569 - Professional supplies, services"                   
 [84] "124 - Playground"                                        
 [85] "363 - Reformatory, juvenile detention center"            
 [86] "974 - Aircraft loading area"                             
 [87] "464 - Barracks, dormitory"                               
 [88] "635 - Computer center"                                   
 [89] "211 - Preschool"                                         
 [90] "186 - Film/movie production studio"                      
 [91] "181 - Live performance theater"                          
 [92] "134 - Funeral parlor"                                    
 [93] "984 - Industrial plant yard - area"                      
 [94] "629 - Laboratory or science lababoratory"                
 [95] "144 - Casino, gambling clubs"                            
 [96] "936 - Vacant lot"                                        
 [97] "254 - Day care, in commercial property"                  
 [98] "155 - Courthouse"                                        
 [99] "807 - Outside material storage area"                     
[100] "250 - Day care, other (Conversion only)"                 
[101] "615 - Electric-generating plant"                         
[102] "213 - Elementary school, including kindergarten"         
[103] "143 - Yacht Club"                                        
[104] "341 - Clinic, clinic-type infirmary"                     
[105] "639 - Communications center"                             
[106] "898 - Dock, marina, pier, wharf"                         
[107] "952 - Railroad yard"                                     
There were 50 or more warnings (use warnings() to see the first 50)
highest_alarm %>%
  group_by(PROPERTY_USE_DESC) %>%
  count()%>%
  arrange(desc (n))
library(stringr)
highest_alarm['class']=list(str_sub(highest_alarm$PROPERTY_USE_DESC,1,1))

highest_alarm$class[highest_alarm$class == "1"] <- "Assembly"
highest_alarm$class[highest_alarm$class == "2"] <- "Educational"
highest_alarm$class[highest_alarm$class == "3"] <- "Healthcare, Detention and Correction"
highest_alarm$class[highest_alarm$class == "4"] <- "Residential"
highest_alarm$class[highest_alarm$class == "5"] <- "Mercantile and Business"
highest_alarm$class[highest_alarm$class == "6"] <- "Energy Production Plant"
highest_alarm$class[highest_alarm$class == "7"] <- "Manufacturing and Processing"
highest_alarm$class[highest_alarm$class == "8"] <- "Storage"
highest_alarm$class[highest_alarm$class %in% c("9","U","N","0")] <- "Other Property"

highest_alarm$class <- factor(highest_alarm$class, levels= c("Assembly","Educational","Healthcare, Detention and Correction", "Residential", "Mercantile and Business", "Energy Production Plant", "Manufacturing and Processing", "Storage", "Other Property"))

highest_alarm %>%
  group_by(class) %>%
  count() %>%
  arrange(desc(n))
library(RColorBrewer)

pal <- colorFactor(palette = "Set3", levels = c("Assembly","Educational","Healthcare, Detention and Correction", "Residential", "Mercantile and Business", "Energy Production Plant", "Manufacturing and Processing", "Storage", "Other Property"))

property_map <- leaflet(highest_alarm, options = leafletOptions(minZoom = 5, dragging = TRUE))%>%
  addProviderTiles(provider = "CartoDB")%>%
  setView( lat= 40.712742, lng=-74.013382, zoom = 10 ) %>%
  addCircleMarkers(lng = ~lon,lat = ~lat, radius = 1, color = ~pal(class), popup = ~paste0("<b>","Property Type: ", class,"</b>","<br/>","Date: ",str_extract(INCIDENT_DATE_TIME, pattern = "[0-9]+/[0-9]+/[0-9]+"), "<br/>", "Address: ", address, "<br/>", "Spread: ", str_sub(FIRE_SPREAD_DESC, 5,-1)))%>%
  addLegend(pal = pal, values = c("Assembly","Educational","Healthcare, Detention and Correction", "Residential", "Mercantile and Business", "Energy Production Plant", "Manufacturing and Processing", "Storage", "Other Property"), opacity = 0.8, title = "Property Affected",position = "topleft")

property_map

saveWidget(property_map, file="property_map.html")
b) Cluster

Add marker clustering, so that zooming in will reveal the individual locations but the zoomed out map only shows the clusters. Show the map with clusters.

cluster_property_map <- leaflet(highest_alarm, options = leafletOptions(minZoom = 5, dragging = TRUE))%>%
  addProviderTiles(provider = "CartoDB")%>%
  setView( lat= 40.712742, lng=-74.013382, zoom = 10 ) %>%
  addCircleMarkers(lng = ~lon,lat = ~lat, radius = 1, color = ~pal(class), clusterOptions = markerClusterOptions(), popup = ~paste0("<b>","Property Type: ", class,"</b>","<br/>","Date: ",str_extract(INCIDENT_DATE_TIME, pattern = "[0-9]+/[0-9]+/[0-9]+"), "<br/>", "Address: ", address, "<br/>", "Spread: ", str_sub(FIRE_SPREAD_DESC, 5,-1)))%>%
  addLegend(pal = pal, values = c("Assembly","Educational","Healthcare, Detention and Correction", "Residential", "Mercantile and Business", "Energy Production Plant", "Manufacturing and Processing", "Storage", "Other Property"), opacity = 0.8, title = "Property Affected",position = "topleft")

cluster_property_map

saveWidget(cluster_property_map, file="cluster_property_map.html")

3. Fire Houses

The second data file contains the locations of the 218 firehouses in New York City. Start with the non-clustered map (2b) and now adjust the size of the circle markers by severity (TOTAL_INCIDENT_DURATION or UNITS_ONSCENE seem plausible options). More severe incidents should have larger circles on the map. On the map, also add the locations of the fire houses. Add two layers (“Incidents”, “Firehouses”) that allow the user to select which information to show.

#highest_alarm$TOTAL_INCIDENT_DURATION)
summary(highest_alarm$TOTAL_INCIDENT_DURATION)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
    870    4907    6803    7308    8918  428335       1 
incidents_firehouse_map <-leaflet(highest_alarm, options = leafletOptions(minZoom = 5, dragging = TRUE))%>%
  addProviderTiles(provider = "CartoDB")%>%
  setView( lat= 40.712742, lng=-74.013382, zoom = 10 ) %>%
  addCircleMarkers(lng = ~lon,lat = ~lat, radius = ~TOTAL_INCIDENT_DURATION/5000 , color = ~pal(class), popup = ~paste0("<b>","Property Type: ", class,"</b>","<br/>","Date: ",str_extract(INCIDENT_DATE_TIME, pattern = "[0-9]+/[0-9]+/[0-9]+"), "<br/>", "Address: ", address, "<br/>", "Spread: ", str_sub(FIRE_SPREAD_DESC, 5,-1)), group = "Incidents")%>%
  addLegend(pal = pal, values = c("Assembly","Educational","Healthcare, Detention and Correction", "Residential", "Mercantile and Business", "Energy Production Plant", "Manufacturing and Processing", "Storage", "Other Property"), opacity = 0.8, title = "Property Affected",position = "topleft")%>%
  addMarkers(data = firehouses, lng = ~Longitude, lat = ~Latitude, group = "Firehouses")%>%
  addLayersControl(overlayGroups = c("Incidents", "Firehouses"))
incidents_firehouse_map

saveWidget(incidents_firehouse_map, file="incidents_firehouse_map.html")

4. Distance from Firehouse and Response Time

We now want to investigate whether the distance of the incident from the nearest firehouse varies across the city.

a) Calculate Distance

For all incident locations (independent of severity), identify the nearest firehouse and calculate the distance between the firehouse and the incident location. Provide a scatter plot showing the time until the first engine arrived (the variables INCIDENT_DATE_TIME and ARRIVAL_DATE_TIME) will be helpful.

library(sp)
library(sf)
Linking to GEOS 3.7.2, GDAL 2.4.2, PROJ 5.2.0
library(raster)

Attaching package: ‘raster’

The following object is masked from ‘package:dplyr’:

    select

The following object is masked from ‘package:tidyr’:

    extract
library(rgeos)
rgeos version: 0.5-2, (SVN revision 621)
 GEOS runtime version: 3.7.2-CAPI-1.11.2 
 Linking to sp version: 1.3-1 
 Polygon checking: TRUE 
# transform firehouse into sf object
firehouse_sf <- st_as_sf(firehouses, coords = c("Longitude", "Latitude"), crs = 4326)
# build an empty list to store the nearest distance
nearest <-list()
# iterate the fire_building and transform them into sp objects 
# use st_distance to calculate the distances and find the nearest firehouse
for(i in 1:nrow(fire_building)){
  point_sf <- st_as_sf(fire_building[i,], coords = c("lon", "lat"), crs = 4326)
  nearest[i] <- min(st_distance(point_sf, firehouse_sf))
}
length(nearest)
[1] 14200
any(is.na(nearest))
[1] FALSE
# create a new column in fire_building about the nearest distance from firehouse
fire_building['distance'] <- unlist(nearest)
distance_and_time <- fire_building %>%
  dplyr::select(INCIDENT_DATE_TIME, ARRIVAL_DATE_TIME, PROPERTY_USE_DESC,HIGHEST_LEVEL_DESC,BOROUGH_DESC, lon, lat, distance)
head(distance_and_time)
incident_time <- as.POSIXct(strptime(distance_and_time[['INCIDENT_DATE_TIME']], format = "%m/%d/%Y %H:%M:%S %p"))
arrival_time <- as.POSIXct(strptime(distance_and_time[['ARRIVAL_DATE_TIME']], format = "%m/%d/%Y %H:%M:%S %p"))
waiting_time <- arrival_time-incident_time
distance_and_time['waiting_time_secs'] <- as.numeric(waiting_time)
#There are some mistakes in original records like wrong AM/PM
#Transfrom those wrong records (negative numbers) by adding 12 hours back
for(i in 1:nrow(distance_and_time)){
  if (!is.na(distance_and_time[i,'waiting_time_secs'])&distance_and_time[i,'waiting_time_secs'] < 0) {
    distance_and_time[i,'waiting_time_secs'] <- distance_and_time[i,'waiting_time_secs']+12*60*60
  }
}
head(distance_and_time)
summary(distance_and_time)
 INCIDENT_DATE_TIME ARRIVAL_DATE_TIME  PROPERTY_USE_DESC  HIGHEST_LEVEL_DESC BOROUGH_DESC            lon        
 Length:14200       Length:14200       Length:14200       Length:14200       Length:14200       Min.   :-74.25  
 Class :character   Class :character   Class :character   Class :character   Class :character   1st Qu.:-73.97  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character   Mode  :character   Median :-73.92  
                                                                                                Mean   :-73.92  
                                                                                                3rd Qu.:-73.87  
                                                                                                Max.   :-73.09  
                                                                                                                
      lat           distance         waiting_time_secs
 Min.   :40.50   Min.   :     7.75   Min.   :   12.0  
 1st Qu.:40.67   1st Qu.:   362.06   1st Qu.:  172.0  
 Median :40.72   Median :   561.04   Median :  208.0  
 Mean   :40.73   Mean   :   666.23   Mean   :  421.1  
 3rd Qu.:40.80   3rd Qu.:   863.99   3rd Qu.:  250.0  
 Max.   :41.60   Max.   :101812.17   Max.   :86816.0  
                                     NA's   :23       
library(ggplot2)
library(ggthemes)
library(plotly)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     

Attaching package: ‘plotly’

The following object is masked from ‘package:raster’:

    select

The following object is masked from ‘package:ggmap’:

    wind

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
df_plot <-distance_and_time %>%
  filter(!is.na(waiting_time_secs))%>%
  filter(distance < 5000) %>%
  filter(waiting_time_secs < 5000)
p <-ggplot(df_plot, aes(x = distance, y = waiting_time_secs))+
  geom_point(alpha = 0.5)+
  labs(x = "Distance From The Nearest Firehouse (m)", y = "Waiting Time For The First Engine (secs)")+
  theme_clean()
p

Now also visualize the patterns separately for severe and non-severe incidents (use HIGHEST_LEVEL_DESC but feel free to reduce the number of categories). What do you find?

fire_levels <- distance_and_time%>%
  filter(!is.na(HIGHEST_LEVEL_DESC))
fire_levels['level']=list(str_sub(fire_levels$HIGHEST_LEVEL_DESC,1,2))
fire_levels$level[fire_levels$level %in% c("7 ", "75")] <- "High Alarm"
fire_levels$level[fire_levels$level %in% c("5 ", "55", "4 ", "44", "3 ", "33")] <- "Medium Alarm"
fire_levels$level[fire_levels$level %in% c("2 ", "22", "11", "0 ")] <- "Low Alarm"
fire_levels$level[fire_levels$level %in% c("1 ")] <- "Undefined Alarm"
fire_levels$level <- factor(fire_levels$level, levels= c("Low Alarm","Medium Alarm","High Alarm","Undefined Alarm"))
fire_levels_plot <- fire_levels %>%
  filter(!is.na(waiting_time_secs))%>%
  filter(distance < 5000) %>%
  filter(waiting_time_secs < 1000)
ggplot(fire_levels_plot, aes(x=waiting_time_secs, y=distance, color = level))+
  geom_point(alpha=0.4)+
  facet_grid(~ level)+
  labs(x = "Waiting Time For The First Engine (secs)", y = "Distance From The Nearest Firehouse (m)")+
  theme_bw()

b) Map of Response Times

Provide a map visualization of response times. Investigate whether the type of property affected (PROPERTY_USE_DESC) or fire severity (HIGHEST_LEVEL_DESC) play a role here.

response_time <- fire_levels
response_time['class']=list(str_sub(response_time$PROPERTY_USE_DESC,1,1))

response_time$class[response_time$class == "1"] <- "Assembly"
response_time$class[response_time$class == "2"] <- "Educational"
response_time$class[response_time$class == "3"] <- "Healthcare, Detention and Correction"
response_time$class[response_time$class == "4"] <- "Residential"
response_time$class[response_time$class == "5"] <- "Mercantile and Business"
response_time$class[response_time$class == "6"] <- "Energy Production Plant"
response_time$class[response_time$class == "7"] <- "Manufacturing and Processing"
response_time$class[response_time$class == "8"] <- "Storage"
response_time$class[response_time$class %in% c("9","U","N","0")] <- "Other Property"

response_time$class <- factor(response_time$class, levels= c("Assembly","Educational","Healthcare, Detention and Correction", "Residential", "Mercantile and Business", "Energy Production Plant", "Manufacturing and Processing", "Storage", "Other Property"))
head(response_time)
low <- filter(response_time, level == "Low Alarm")
medium <- filter(response_time, level == "Medium Alarm")
high <- filter(response_time, level == "High Alarm")
pal_level <- colorFactor(palette = c("#f03b20", "#feb24c", "#ffeda0"), 
                   levels = c("High Alarm","Medium Alarm","Low Alarm"))
alarm_map <- leaflet(options = leafletOptions(minZoom = 8, dragging = TRUE)) %>%
  addProviderTiles("CartoDB.DarkMatter",options = providerTileOptions(attribution = ""))%>%
  addCircleMarkers(data = low, lng = ~lon, lat = ~lat, radius = ~waiting_time_secs/5000, fillOpacity=0.3,
                         color = ~pal_level(level),  group = "Low Alarm", popup=~paste("Alarm Level: ",level,
                           "<br>Response Time: ", waiting_time_secs," seconds", "<br>Property Type: ", class)) %>% 
  addCircleMarkers(data = medium, lng = ~lon, lat = ~lat, radius = ~waiting_time_secs/5000, fillOpacity=0.3,
                         color = ~pal_level(level),  group = "Medium Alarm", popup=~paste("Alarm Level: ",level,
                           "<br>Response Time: ", waiting_time_secs, " seconds", "<br>Property Type: ", class)) %>%  
  addCircleMarkers(data = high, lng = ~lon, lat = ~lat, radius = ~waiting_time_secs/5000, fillOpacity=0.3,
                         color = ~pal_level(level),  group = "High Alarm", popup=~paste("Alarm Level: ",level,
                           "<br>Response Time: ", waiting_time_secs, " seconds", "<br>Property Type: ", class)) %>%
        setView(lat= 40.712742, lng=-74.013382, zoom = 10) %>%
        addLegend(pal = pal_level, values = c("High Alarm","Medium Alarm", "Low Alarm"), opacity = 0.7, title = "Alarm Level",
                                       position = "topleft")%>%
        addLayersControl(overlayGroups = c("High Alarm","Medium Alarm","Low Alarm"))
alarm_map

saveWidget(alarm_map, file="alarm_map.html")
long_response <- subset(response_time, waiting_time_secs > 500)
fireIcons <- icons(
  iconUrl = "data/redflame.png",
  iconWidth = 15, iconHeight = 15,
  iconAnchorX = 7.5, iconAnchorY = 8.5
  )
pal_class <- colorFactor(palette = "Tableau10", levels = c("Assembly","Educational","Healthcare, Detention and Correction", "Residential", "Mercantile and Business", "Energy Production Plant", "Manufacturing and Processing", "Storage", "Other Property"))

response_residential <- leaflet(options = leafletOptions(minZoom = 5, dragging = TRUE))%>%
addProviderTiles(provider = "CartoDB") %>%
addCircleMarkers(data = response_time, lng = ~lon, lat = ~lat, radius = ~waiting_time_secs/5000, color = ~pal_class(class), 
                 fillOpacity=0.3, popup = ~paste("Property Type: ", class, "<br>Response Time: ", waiting_time_secs," seconds"))%>%
  addMarkers(data= long_response,icon = fireIcons, 
             popup = ~paste("Property Type: ", class, "<br>Response Time: ", waiting_time_secs," seconds"))%>%
  setView( lat= 40.712742, lng=-74.013382, zoom = 10 )
Assuming "lon" and "lat" are longitude and latitude, respectively
response_residential

#saveWidget(response_residential, file="response_residential.html")

According to the plot above, those big circles and fire flame icons are the incidents with a long response time.Clicking the popup, we can see most of them are residential properties. Then we remove those “Residential” records and find some incidents happened in businesses and assembly also had a long response time.

fireIcons2 <- icons(
  iconUrl = "data/flame.png",
  iconWidth = 15, iconHeight = 15,
  iconAnchorX = 7.5, iconAnchorY = 8.5
  )

pal_property <- colorFactor(palette = "Spectral", levels = c("Assembly","Educational","Healthcare, Detention and Correction","Mercantile and Business", "Energy Production Plant", "Manufacturing and Processing", "Storage", "Other Property"))

response_property_map <- leaflet(options = leafletOptions(minZoom = 5, dragging = TRUE))%>%
addProviderTiles("Esri.WorldImagery", options = providerTileOptions(attribution = "")) %>%
addCircleMarkers(data = subset(response_time, response_time$class != "Residential"), lng = ~lon, lat = ~lat, radius = ~waiting_time_secs/5000, color = ~pal_property(class), fillOpacity=0.7, popup = ~paste("Property Type: ", class, "<br>Response Time: ", waiting_time_secs," seconds"))%>%
  addMarkers(data= subset(long_response, long_response$class != "Residential"),icon = fireIcons2, 
             popup = ~paste("Property Type: ", class, "<br>Response Time: ", waiting_time_secs," seconds"))%>%
  addLegend(pal = pal_property, values = c("Assembly","Educational","Healthcare, Detention and Correction","Mercantile and Business", "Energy Production Plant", "Manufacturing and Processing", "Storage", "Other Property"), opacity = 0.7, title = "Property Affected",position = "topleft")%>%
  setView( lat= 40.712742, lng=-74.013382, zoom = 10 )
Assuming "lon" and "lat" are longitude and latitude, respectively
response_property_map

#saveWidget(response_property_map, file="response_property_map.html")

Show a faceted choropleth map indicating how response times have developed over the years. What do you find?

response_borough<-distance_and_time %>%
  select(INCIDENT_DATE_TIME,BOROUGH_DESC, waiting_time_secs)
response_borough['borough'] = list(str_sub(response_borough$BOROUGH_DESC,1,1))
response_borough$borough[response_borough$borough == "1"] <- "Manhattan"
response_borough$borough[response_borough$borough == "2"] <- "Bronx"
response_borough$borough[response_borough$borough == "3"] <- "Staten Island"
response_borough$borough[response_borough$borough == "4"] <- "Brooklyn"
response_borough$borough[response_borough$borough == "5"] <- "Queens"
response_borough$borough <- factor(response_borough$borough, levels= c("Manhattan","Bronx","Staten Island","Brooklyn","Queens"))
response_borough['year'] = list(str_sub(response_borough$INCIDENT_DATE_TIME,7,10))
response_borough$year <- factor(response_borough$year, levels= c("2013","2014","2015","2016","2017","2018"))
head(response_borough)
subset(response_borough, response_borough$borough == "Queens"&response_borough$year =="2013")
average_response_time <-response_borough %>%
  filter(!is.na(waiting_time_secs))%>%
  group_by(borough, year) %>%
  summarise(mean_response_time = round(mean(waiting_time_secs),2))
average_response_time
library(rgdal)
rgdal: version: 1.4-8, (SVN revision 845)
 Geospatial Data Abstraction Library extensions to R successfully loaded
 Loaded GDAL runtime: GDAL 2.4.2, released 2019/06/28
 Path to GDAL shared files: /Library/Frameworks/R.framework/Versions/3.6/Resources/library/rgdal/gdal
 GDAL binary built with GEOS: FALSE 
 Loaded PROJ.4 runtime: Rel. 5.2.0, September 15th, 2018, [PJ_VERSION: 520]
 Path to PROJ.4 shared files: /Library/Frameworks/R.framework/Versions/3.6/Resources/library/rgdal/proj
 Linking to sp version: 1.3-2 
borough <- readOGR("data/borough_boundaries.geojson", verbose=FALSE)
borough@data
shp_response <- borough@data %>%
  right_join(average_response_time, by = c("boro_name"= "borough"))
Column `boro_name`/`borough` joining factors with different levels, coercing to character vector
shp_response
borough@data <-shp_response %>%
  filter(year =="2013")
summary(borough$mean_response_time)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  231.6   351.8   387.8   393.4   497.8   498.3 
pal_response <- colorNumeric("PuOr", domain = borough$mean_response_time)
map2013 <-borough %>%
  leaflet()%>%
  addProviderTiles("CartoDB")%>%
  addPolygons(weight = 1, color = ~pal_response(mean_response_time), fillOpacity = 1,
              label = ~paste0("Mean Response Time: ", mean_response_time, "seconds"),
              highlightOptions = highlightOptions(weight = 5, color = "white", bringToFront = TRUE))%>%
  addLegend(pal = pal_response, values = ~ mean_response_time, title = "2013",
            position = "topleft", opacity=0.7)
borough@data <-shp_response %>%
  filter(year =="2014")
summary(borough$mean_response_time)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  234.8   297.1   380.4   465.0   492.6   920.3 
pal_response <- colorNumeric("PuOr", domain = borough$mean_response_time)
map2014 <-borough %>%
  leaflet()%>%
  addProviderTiles("CartoDB")%>%
  addPolygons(weight = 1, color = ~pal_response(mean_response_time), fillOpacity = 1,
              label = ~paste0("Mean Response Time: ", mean_response_time, "seconds"),
              highlightOptions = highlightOptions(weight = 5, color = "white", bringToFront = TRUE))%>%
  addLegend(pal = pal_response, values = ~ mean_response_time, title = "2014",
            position = "topleft", opacity=0.7)
borough@data <-shp_response %>%
  filter(year =="2015")
summary(borough$mean_response_time)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  188.1   217.4   396.9   336.6   398.4   482.6 
pal_response <- colorNumeric("PuOr", domain = borough$mean_response_time)
map2015 <-borough %>%
  leaflet()%>%
  addProviderTiles("CartoDB")%>%
  addPolygons(weight = 1, color = ~pal_response(mean_response_time), fillOpacity = 1,
              label = ~paste0("Mean Response Time: ", mean_response_time, "seconds"),
              highlightOptions = highlightOptions(weight = 5, color = "white", bringToFront = TRUE))%>%
  addLegend(pal = pal_response, values = ~ mean_response_time, title = "2013",
            position = "topleft", opacity=0.7)
borough@data <-shp_response %>%
  filter(year =="2016")
summary(borough$mean_response_time)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  226.1   233.4   359.7   353.4   410.7   537.0 
pal_response <- colorNumeric("PuOr", domain = borough$mean_response_time)
map2016 <-borough %>%
  leaflet()%>%
  addProviderTiles("CartoDB")%>%
  addPolygons(weight = 1, color = ~pal_response(mean_response_time), fillOpacity = 1,
              label = ~paste0("Mean Response Time: ", mean_response_time, "seconds"),
              highlightOptions = highlightOptions(weight = 5, color = "white", bringToFront = TRUE))%>%
  addLegend(pal = pal_response, values = ~ mean_response_time, title = "2016",
            position = "topleft", opacity=0.7)
borough@data <-shp_response %>%
  filter(year =="2017")
summary(borough$mean_response_time)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  223.3   228.8   427.3   410.8   535.7   638.9 
pal_response <- colorNumeric("PuOr", domain = borough$mean_response_time)
map2017 <-borough %>%
  leaflet()%>%
  addProviderTiles("CartoDB")%>%
  addPolygons(weight = 1, color = ~pal_response(mean_response_time), fillOpacity = 1,
              label = ~paste0("Mean Response Time: ", mean_response_time, "seconds"),
              highlightOptions = highlightOptions(weight = 5, color = "white", bringToFront = TRUE))%>%
  addLegend(pal = pal_response, values = ~ mean_response_time, title = "2017",
            position = "topleft", opacity=0.7)
borough@data <-shp_response %>%
  filter(year =="2018")
summary(borough$mean_response_time)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  236.0   244.1   246.9   396.6   248.8  1007.0 
pal_response <- colorNumeric("PuOr", domain = borough$mean_response_time)
map2018 <-borough %>%
  leaflet()%>%
  addProviderTiles("CartoDB")%>%
  addPolygons(weight = 1, color = ~pal_response(mean_response_time), fillOpacity = 1,
              label = ~paste0("Mean Response Time: ", mean_response_time, "seconds"),
              highlightOptions = highlightOptions(weight = 5, color = "white", bringToFront = TRUE))%>%
  addLegend(pal = pal_response, values = ~ mean_response_time, title = "2018",
            position = "topleft", opacity=0.7)
library(mapview)
facet_map <- sync(map2013, map2014, map2015, map2016, map2017,map2018, ncol = 3, sync = "all")
'mapview::sync' is deprecated.
Use 'leafsync::sync' instead.
See help("Deprecated") and help("leafsync-deprecated").'mapview::latticeView' is deprecated.
Use 'leafsync::latticeView' instead.
See help("Deprecated") and help("mapview-deprecated").
facet_map

Submission

Please follow the instructions to submit your homework. The homework is due on Wednesday, March 25.

Please stay honest!

If you do come across something online that provides part of the analysis / code etc., please no wholesale copying of other ideas. We are trying to evaluate your abilities to visualize data, not the ability to do internet searches. Also, this is an individually assigned exercise – please keep your solution to yourself.

LS0tCnRpdGxlOiAiSG9tZXdvcmsgMiAtIEZpcmVzIgphdXRob3I6ICJYdWV5aW5nIEh1YW5nIgpkYXRlOiAnMjAyMC0wMy0xOScKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQogICAgdGhlbWU6IHNwYWNlbGFiCiAgICB0b2M6IHllcwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgd29yZF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCmFsd2F5c19hbGxvd19odG1sOiB5ZXMKLS0tCgpGaXJlcyBpbiBOWUMgYW5kIEZETlkgUmVzcG9uc2UKPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCmBgYHtyIFNldHVwLCBpbmNsdWRlPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgd2FybmluZz1GQUxTRX0KbGlicmFyeShrbml0cikKb3B0c19jaHVuayRzZXQoZmlnLnBhdGg9ImZpZ3VyZXMvIiwKICAgICAgICAgICAgICAgY2FjaGUucGF0aD0iY2FjaGUvIiwKICAgICAgICAgICAgICAgY2FjaGU9RkFMU0UsCiAgICAgICAgICAgICAgIGVjaG89VFJVRSwKICAgICAgICAgICAgICAgbWVzc2FnZT1GQUxTRSwKICAgICAgICAgICAgICAgd2FybmluZz1GQUxTRSkgIApgYGAgIAojIyBPdmVydmlldwoKRm9yIHRoaXMgYXNzaWdubWVudCwgd2UgYXJlIGdvaW5nIHRvIGludmVzdGlnYXRlIGZpcmVzIHJlcXVpcmluZyB0aGUgZmlyZSBkZXBhcnRtZW50IHRvIHJlc3BvbmQuIFVzaW5nIGRhdGEgYWJvdXQgdGhlIGxvY2F0aW9ucyBvZiBmaXJlaG91c2VzIGFuZCBmaXJlcyBvY2N1cnJpbmcgaW4gTmV3IFlvcmsgQ2l0eSwgd2Ugd2FudCB0byBrbm93IHdoZXRoZXIgcmVzcG9uc2UgdGltZXMgdG8gZmlyZXMgZGlmZmVyIGFjcm9zcyB0aGUgY2l0eS4gU2Vjb25kLCB3ZSB3aWxsIHRyeSB0byBmb2N1cyBvbiBvbmUgcG9zc2libGUgdmFyaWFibGUgdGhhdCBjb3VsZCBhZmZlY3QgcmVzcG9uc2UgdGltZXMgLS0gdGhlIGRpc3RhbmNlIGZyb20gdGhlIGZpcmVob3VzZSAtLSBhbmQgc2VlIHdoZXRoZXIgd2UgZmluZCB0aGUgKGV4cGVjdGVkKSBlZmZlY3QuCgpUbyBrZWVwIHRoaXMgaG9tZXdvcmsgbWFuYWdlYWJsZSwgSSBhbSBsZWF2aW5nIG91dCBhbm90aGVyIHBhcnQgb2YgdGhlIGludmVzdGlnYXRpb246IFdoYXQgaXMgdGhlIGVmZmVjdCBvZiBkZW1vZ3JhcGhpYyBhbmQvb3IgaW5jb21lIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgbmVpZ2hib3Job29kIG9uIHJlc3BvbnNlIHRpbWVzLiBUaGlzIGlzIGxpa2VseSBhIGJpdCBtb3JlIHNlbnNpdGl2ZSBidXQgYWxzbyByZWxldmFudCBmcm9tIGEgcHVibGljIHBvbGljeSBwZXJzcGVjdGl2ZS4gIAoKIyMgRGF0YQoKV2UgcmVseSBvbiB0d28gZGF0YSBzZXRzLgoKIyMjIyBJbmNpZGVudHMgcmVzcG9uZGVkIHRvIGJ5IGZpcmUgY29tcGFuaWVzCgpOWUMgT3BlbiBEYXRhIGhhcyBkYXRhIG9uIGFsbCBbaW5jaWRlbnRzIHJlc3BvbmRlZCB0byBieSBmaXJlIGNvbXBhbmllc10oaHR0cHM6Ly9kYXRhLmNpdHlvZm5ld3lvcmsudXMvUHVibGljLVNhZmV0eS9JbmNpZGVudHMtUmVzcG9uZGVkLXRvLWJ5LUZpcmUtQ29tcGFuaWVzL3RtNmQtaGJ6ZCkuIEkgaGF2ZSBpbmNsdWRlZCB0aGUgdmFyaWFibGUgZGVzY3JpcHRpb24gZmlsZSBpbiB0aGUgZXhlcmNpc2UgZm9sZGVyLiBUaGUgZm9sbG93aW5nIHZhcmlhYmxlcyBhcmUgYXZhaWxhYmxlOgoKICAtIElNX0lOQ0lERU5UX0tFWToJVW5pcXVlIGlkZW50aWZpZXIgZm9yIGVhY2ggaW5jaWRlbnQgd2hpY2ggc2VydmVzCiAgLSBJTkNJREVOVF9UWVBFX0RFU0MJVGhlIGNvZGUgYW5kIGRlc2NyaXB0aW9uIG9mIHRoZSBpbmNpZGVudCBjYXRlZ29yeSB0eXBlCiAgLSBJTkNJREVOVF9EQVRFX1RJTUUJVGhlIGRhdGUgYW5kIHRpbWUgdGhhdCB0aGUgaW5jaWRlbnQgd2FzIGxvZ2dlZCBpbnRvIHRoZSBDb21wdXRlciBBaWRlZCBEaXNwYXRjaCBzeXN0ZW0KICAtIEFSUklWQUxfREFURV9USU1FCVRoZSBkYXRlIGFuZCB0aW1lIHRoYXQgdGhlIGZpcnN0IHVuaXQgYXJyaXZlZCBvbiBzY2VuZQogIC0gVU5JVFNfT05TQ0VORQlUb3RhbCBudW1iZXIgb2YgdW5pdHMgdGhhdCBhcnJpdmVkIG9uIHNjZW5lCiAgLSBMQVNUX1VOSVRfQ0xFQVJFRF9EQVRFVElNRQlUaGUgZGF0ZSBhbmQgdGltZSB0aGF0IHRoZSBpbmNpZGVudCB3YXMgY29tcGxldGVkIGFuZCB0aGUgbGFzdCB1bml0IGNsZWFyZWQgdGhlIHNjZW5lCiAgLSBISUdIRVNUX0xFVkVMX0RFU0MJVGhlIGhpZ2hlc3QgYWxhcm0gbGV2ZWwgdGhhdCB0aGUgaW5jaWRlbnQgcmVjZWl2ZWQKICAtIFRPVEFMX0lOQ0lERU5UX0RVUkFUSU9OCVRoZSB0b3RhbCBudW1iZXIgb2Ygc2Vjb25kcyBmcm9tIHdoZW4gdGhlbiBpbmNpZGVudCB3YXMgY3JlYXRlZCB0byB3aGVuIHRoZSBpbmNpZGVudCB3YXMgY2xvc2VkCiAgLSBBQ1RJT05fVEFLRU4xX0RFU0MJVGhlIGNvZGUgYW5kIGRlc2NyaXB0aW9uIG9mIHRoZSBmaXJzdCBhY3Rpb24gdGFrZW4KICAtIEFDVElPTl9UQUtFTjJfREVTQwlUaGUgY29kZSBhbmQgZGVzY3JpcHRpb24gb2YgdGhlIHNlY29uZCBhY3Rpb24gdGFrZW4KICAtIEFDVElPTl9UQUtFTjNfREVTQwlUaGUgY29kZSBhbmQgZGVzY3JpcHRpb24gb2YgdGhlIHRoaXJkIGFjdGlvbiB0YWtlbgogIC0gUFJPUEVSVFlfVVNFX0RFU0MJVGhlIGNvZGUgYW5kIGRlc2NyaXB0aW9uIG9mIHRoZSB0eXBlIG9mIHN0cmVldCBvciBidWlsZGluZyB3aGVyZSB0aGUgaW5jaWRlbnQgdG9vayBwbGFjZQogIC0gU1RSRUVUX0hJR0hXQVkJVGhlIG5hbWUgb2YgdGhlIHN0cmVldCB3aGVyZSB0aGUgaW5jaWRlbnRfdG9vayBwbGFjZQogIC0gWklQX0NPREUJVGhlIHBvc3RhbCB6aXAgY29kZSB3aGVyZSB0aGUgaW5jaWRlbnQgdG9vayBwbGFjZQogIC0gQk9ST1VHSF9ERVNDCVRoZSBib3JvdWdoIHdoZXJlIHRoZSBpbmNpZGVudCB0b29rIHBsYWNlCiAgLSBGTE9PUglUaGUgZmxvb3Igb2YgdGhlIGJ1aWxkaW5nIHdoZXJlIHRoZSBpbmNpZGVudCB0b29rIHBsYWNlCiAgLSBDT19ERVRFQ1RPUl9QUkVTRU5UX0RFU0MJSW5kaWNhdG9yIGZvciB3aGVuIGEgQ08gZGV0ZWN0b3Igd2FzIHByZXNlbnQKICAtIEZJUkVfT1JJR0lOX0JFTE9XX0dSQURFX0ZMQUcJSW5kaWNhdG9yIGZvciB3aGVuIHRoZSBmaXJlIG9yaWdpbmF0ZWQgYmVsb3cgZ3JhZGUKICAtIFNUT1JZX0ZJUkVfT1JJR0lOX0NPVU5UCVN0b3J5IGluIHdoaWNoIHRoZSBmaXJlIG9yaWdpbmF0ZWQKICAtIEZJUkVfU1BSRUFEX0RFU0MJSG93IGZhciB0aGUgZmlyZSBzcHJlYWQgZnJvbSB0aGUgb2JqZWN0IG9mIG9yaWdpbgogIC0gREVURUNUT1JfUFJFU0VOQ0VfREVTQwlJbmRpY2F0b3IgZm9yIHdoZW4gYSAgZGV0ZWN0b3Igd2FzIHByZXNlbnQKICAtIEFFU19QUkVTRU5DRV9ERVNDCUluZGljYXRvciBmb3Igd2hlbiBhbiBBdXRvbWF0aWMgRXh0aW5ndWlzaGluZyBTeXN0ZW0gaXMgcHJlc2VudAogIC0gU1RBTkRQSVBFX1NZU19QUkVTRU5UX0ZMQUcJSW5kaWNhdG9yIGZvciB3aGVuIGEgc3RhbmRwaXBlIHdhcyBwcmVzZW50IGluIHRoZSBhcmVhIG9mIG9yaWdpbiBvZiBhIGZpcmUKClRoaXMgZGF0YXNldCBpcyBvbmx5IHVwZGF0ZWQgYW5udWFsbHksIGFuZCB0aHVzIGZhciBvbmx5IGRhdGEgZnJvbSAyMDEzIHRvIDIwMTggaXMgY29udGFpbmVkLiBUaGUgZnVsbCBkYXRhc2V0IGlzIGFsc28gc29tZXdoYXQgdG9vIGxhcmdlIGZvciBhbiBleGVyY2lzZSAoMi41TSByb3dzKSwgc28gSSBzdWdnZXN0IHRvIGxpbWl0IHlvdXJzZWxmIHRvIGEgc3Vic2V0LiBJIGhhdmUgYWRkZWQgYSBmaWxlIGNvbnRhaW5pbmcgdGhlIHN1YnNldCBvZiBvZiBvbmx5IGJ1aWxkaW5nIGZpcmVzIChgSU5DSURFTlRfVFlQRV9ERVNDID09ICIxMTEgLSBCdWlsZGluZyBmaXJlImApIGZvciAyMDEzIHRvIDIwMTggb25seSB3aGljaCB5aWVsZHMgYWJvdXQgMTQsMDAwIGluY2lkZW50cy4KClVuZm9ydHVuYXRlbHksIHRoZSBhZGRyZXNzZXMgb2YgdGhlIGluY2lkZW50cyB3ZXJlIG5vdCBnZW9jb2RlZCB5ZXQuIElkZWFsbHksIEkgd291bGQgbGlrZSB5b3UgdG8ga25vdyBob3cgdG8gZG8gdGhpcyBidXQgYW0gbWluZGZ1bCBhYm91dCB0aGUgaG91ciBvciBzbyByZXF1aXJlZCB0byBnZXQgdGhpcyBkb25lLiBTbywgaGVyZSBpcyB0aGUgY29kZS4gVGhlIGdlb2NvZGVzIChhcyBmYXIgYXMgdGhleSB3ZXJlIHJldHVybmVkIHN1Y2Nlc3NmdWxseSkgYXJlIHBhcnQgb2YgdGhlIGRhdGEgKGFzIHZhcmlhYmxlcyBgbGF0YCBhbmQgYGxvbmApLgoKYGBge3J9CmxpYnJhcnkoZ2dtYXApCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGRwbHlyKQojIE9wZW4gImJ1aWxkaW5nX2ZpcmVzIiBmaWxlCmZpcmVfYnVpbGRpbmcgPC0gcmVhZF9jc3YoImRhdGEvYnVpbGRpbmdfZmlyZXMuY3N2IikKYGBgCgojIyMjIEZETlkgRmlyZWhvdXNlIExpc3RpbmcKCk5ZQyBPcGVuIERhdGEgYWxzbyBwcm92aWRlcyBkYXRhIG9uIHRoZSBbbG9jYXRpb24gb2YgYWxsIDIxOCBmaXJlaG91c2VzIGluIE5ZQ10oaHR0cHM6Ly9kYXRhLmNpdHlvZm5ld3lvcmsudXMvUHVibGljLVNhZmV0eS9GRE5ZLUZpcmVob3VzZS1MaXN0aW5nL2hjOHgtdGNuZCkuIFJlbGV2YW50IGZvciBvdXIgYW5hbHlzaXMgYXJlIHRoZSBmb2xsb3dpbmcgdmFyaWFibGVzOiBgRmFjaWxpdHlOYW1lYCwgYEJvcm91Z2hgLCBgTGF0aXR1ZGVgLCBgTG9uZ2l0dWRlYAoKYGBge3J9CmZpcmVob3VzZXMgPC0gcmVhZF9jc3YoImRhdGEvRkROWV9GaXJlaG91c2VfTGlzdGluZy5jc3YiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShMYXRpdHVkZSkpCmBgYAoKX05vdGU6XyA1IGVudHJpZXMgY29udGFpbiBtaXNzaW5nIGluZm9ybWF0aW9uLCBpbmNsdWRpbmcgb24gdGhlIHNwYXRpYWwgY29vcmRpbmF0ZXMuIFdlIGNhbiBleGNsdWRlIHRoZXNlIGZvciB0aGUgZXhlcmNpc2UuIAoKIyMgVGFza3MKCiMjIyMgMS4gTG9jYXRpb24gb2YgU2V2ZXJlIEZpcmVzCgpQcm92aWRlIGEgYGxlYWZsZXRgIG1hcCBvZiB0aGUgaGlnaGVzdCBzZXZlcml0eSBmaXJlcyAoaS5lLiBzdWJzZXQgdG8gdGhlIGhpZ2hlc3QgY2F0ZWdvcnkgaW4gYEhJR0hFU1RfTEVWRUxfREVTQ2ApICBjb250YWluZWQgaW4gdGhlIGZpbGUgYGJ1aWRpbmdfZmlyZXMuY3N2YC4gSWdub3JlIGxvY2F0aW9ucyB0aGF0IGZhbGwgb3V0c2lkZSB0aGUgZml2ZSBib3JvdWdocyBvZiBOZXcgWW9yayBDaXR5LiBQcm92aWRlIGF0IGxlYXN0IHRocmVlIHBpZWNlcyBvZiBpbmZvcm1hdGlvbiBvbiB0aGUgaW5jaWRlbnQgaW4gYSBwb3B1cC4gCmBgYHtyfQojIHN1YnNldCB0byB0aGUgaGlnaGVzdCBhbGFybSAKdW5pcXVlKGZpcmVfYnVpbGRpbmckSElHSEVTVF9MRVZFTF9ERVNDKQpoaWdoZXN0X2FsYXJtIDwtIGZpcmVfYnVpbGRpbmcgJT4lCiAgZmlsdGVyKEhJR0hFU1RfTEVWRUxfREVTQz09IjcgLSBTaWduYWwgNy01InwgSElHSEVTVF9MRVZFTF9ERVNDPT0iNzUgLSBBbGwgSGFuZHMgV29ya2luZyIpCnVuaXF1ZShoaWdoZXN0X2FsYXJtJEhJR0hFU1RfTEVWRUxfREVTQykKaGVhZChoaWdoZXN0X2FsYXJtKQpgYGAKYGBge3J9CmxpYnJhcnkobGVhZmxldCkKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGh0bWx3aWRnZXRzKQpoaWdoZXN0X2FsYXJtX21hcCA8LSBsZWFmbGV0KGhpZ2hlc3RfYWxhcm0sIG9wdGlvbnMgPSBsZWFmbGV0T3B0aW9ucyhtaW5ab29tID0gNSwgZHJhZ2dpbmcgPSBUUlVFKSklPiUKICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVyID0gIkVzcmkiKSU+JQogIHNldFZpZXcoIGxhdD0gNDAuNzEyNzQyLCBsbmc9LTc0LjAxMzM4Miwgem9vbSA9IDEwICkgJT4lCiAgYWRkQ2lyY2xlTWFya2VycyhsbmcgPSB+bG9uLGxhdCA9IH5sYXQsIHJhZGl1cyA9IDEsIHBvcHVwID0gfnBhc3RlMCgiRGF0ZTogIixzdHJfZXh0cmFjdChJTkNJREVOVF9EQVRFX1RJTUUsIHBhdHRlcm4gPSAiWzAtOV0rL1swLTldKy9bMC05XSsiKSwgIjxici8+IiwgIkFkZHJlc3M6ICIsIGFkZHJlc3MsICI8YnIvPiIsICJTcHJlYWQ6ICIsIHN0cl9zdWIoRklSRV9TUFJFQURfREVTQywgNSwtMSkpKQpoaWdoZXN0X2FsYXJtX21hcApsaWJyYXJ5KGh0bWx3aWRnZXRzKQojc2F2ZVdpZGdldChoaWdoZXN0X2FsYXJtX21hcCwgZmlsZT0iaGlnaGVzdF9hbGFybV9tYXAuaHRtbCIpCmBgYAoKIyMjIyAyLiBMYXllcnMgYW5kIENsdXN0ZXJzCgojIyMjIyBhKSBDb2xvciBieSBUeXBlIG9mIFByb3BlcnR5CgpTdGFydCB3aXRoIHRoZSBwcmV2aW91cyBtYXAuIE5vdywgZGlzdGluZ3Vpc2ggdGhlIG1hcmtlcnMgb2YgdGhlIGZpcmUgbG9jYXRpb25zIGJ5IGBQUk9QRVJUWV9VU0VfREVTQ2AsIGkuZS4gd2hhdCBraW5kIG9mIHByb3BlcnR5IHdhcyBhZmZlY3RlZC4gSWYgdGhlcmUgYXJlIHRvbyBtYW55IGNhdGVnb3JpZXMsIGNvbGxhcHNlIHNvbWUgY2F0ZWdvcmllcy4gQ2hvb3NlIGFuIGFwcHJvcHJpYXRlIGNvbG9yaW5nIHNjaGVtZSB0byBtYXAgdGhlIGxvY2F0aW9ucyBieSB0eXBlIG9mIGFmZmVjdGVkIHByb3BlcnR5LiBBZGQgYSBsZWdlbmQgaW5mb3JtaW5nIHRoZSB1c2VyIGFib3V0IHRoZSBjb2xvciBzY2hlbWUuIEFsc28gbWFrZSBzdXJlIHRoYXQgdGhlIGluZm9ybWF0aW9uIGFib3V0IHRoZSB0eXBlIG9mIGFmZmVjdGVkIHByb3BlcnR5IGlzIG5vdyBjb250YWluZWQgaW4gdGhlIHBvcHVwIGluZm9ybWF0aW9uLiBTaG93IHRoaXMgbWFwLgpgYGB7cn0KdW5pcXVlKGhpZ2hlc3RfYWxhcm0kUFJPUEVSVFlfVVNFX0RFU0MpCmhpZ2hlc3RfYWxhcm0gJT4lCiAgZ3JvdXBfYnkoUFJPUEVSVFlfVVNFX0RFU0MpICU+JQogIGNvdW50KCklPiUKICBhcnJhbmdlKGRlc2MgKG4pKQpgYGAKYGBge3J9CmxpYnJhcnkoc3RyaW5ncikKaGlnaGVzdF9hbGFybVsnY2xhc3MnXT1saXN0KHN0cl9zdWIoaGlnaGVzdF9hbGFybSRQUk9QRVJUWV9VU0VfREVTQywxLDEpKQoKaGlnaGVzdF9hbGFybSRjbGFzc1toaWdoZXN0X2FsYXJtJGNsYXNzID09ICIxIl0gPC0gIkFzc2VtYmx5IgpoaWdoZXN0X2FsYXJtJGNsYXNzW2hpZ2hlc3RfYWxhcm0kY2xhc3MgPT0gIjIiXSA8LSAiRWR1Y2F0aW9uYWwiCmhpZ2hlc3RfYWxhcm0kY2xhc3NbaGlnaGVzdF9hbGFybSRjbGFzcyA9PSAiMyJdIDwtICJIZWFsdGhjYXJlLCBEZXRlbnRpb24gYW5kIENvcnJlY3Rpb24iCmhpZ2hlc3RfYWxhcm0kY2xhc3NbaGlnaGVzdF9hbGFybSRjbGFzcyA9PSAiNCJdIDwtICJSZXNpZGVudGlhbCIKaGlnaGVzdF9hbGFybSRjbGFzc1toaWdoZXN0X2FsYXJtJGNsYXNzID09ICI1Il0gPC0gIk1lcmNhbnRpbGUgYW5kIEJ1c2luZXNzIgpoaWdoZXN0X2FsYXJtJGNsYXNzW2hpZ2hlc3RfYWxhcm0kY2xhc3MgPT0gIjYiXSA8LSAiRW5lcmd5IFByb2R1Y3Rpb24gUGxhbnQiCmhpZ2hlc3RfYWxhcm0kY2xhc3NbaGlnaGVzdF9hbGFybSRjbGFzcyA9PSAiNyJdIDwtICJNYW51ZmFjdHVyaW5nIGFuZCBQcm9jZXNzaW5nIgpoaWdoZXN0X2FsYXJtJGNsYXNzW2hpZ2hlc3RfYWxhcm0kY2xhc3MgPT0gIjgiXSA8LSAiU3RvcmFnZSIKaGlnaGVzdF9hbGFybSRjbGFzc1toaWdoZXN0X2FsYXJtJGNsYXNzICVpbiUgYygiOSIsIlUiLCJOIiwiMCIpXSA8LSAiT3RoZXIgUHJvcGVydHkiCgpoaWdoZXN0X2FsYXJtJGNsYXNzIDwtIGZhY3RvcihoaWdoZXN0X2FsYXJtJGNsYXNzLCBsZXZlbHM9IGMoIkFzc2VtYmx5IiwiRWR1Y2F0aW9uYWwiLCJIZWFsdGhjYXJlLCBEZXRlbnRpb24gYW5kIENvcnJlY3Rpb24iLCAiUmVzaWRlbnRpYWwiLCAiTWVyY2FudGlsZSBhbmQgQnVzaW5lc3MiLCAiRW5lcmd5IFByb2R1Y3Rpb24gUGxhbnQiLCAiTWFudWZhY3R1cmluZyBhbmQgUHJvY2Vzc2luZyIsICJTdG9yYWdlIiwgIk90aGVyIFByb3BlcnR5IikpCgpoaWdoZXN0X2FsYXJtICU+JQogIGdyb3VwX2J5KGNsYXNzKSAlPiUKICBjb3VudCgpICU+JQogIGFycmFuZ2UoZGVzYyhuKSkKYGBgCmBgYHtyfQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKCnBhbCA8LSBjb2xvckZhY3RvcihwYWxldHRlID0gIlNldDMiLCBsZXZlbHMgPSBjKCJBc3NlbWJseSIsIkVkdWNhdGlvbmFsIiwiSGVhbHRoY2FyZSwgRGV0ZW50aW9uIGFuZCBDb3JyZWN0aW9uIiwgIlJlc2lkZW50aWFsIiwgIk1lcmNhbnRpbGUgYW5kIEJ1c2luZXNzIiwgIkVuZXJneSBQcm9kdWN0aW9uIFBsYW50IiwgIk1hbnVmYWN0dXJpbmcgYW5kIFByb2Nlc3NpbmciLCAiU3RvcmFnZSIsICJPdGhlciBQcm9wZXJ0eSIpKQoKcHJvcGVydHlfbWFwIDwtIGxlYWZsZXQoaGlnaGVzdF9hbGFybSwgb3B0aW9ucyA9IGxlYWZsZXRPcHRpb25zKG1pblpvb20gPSA1LCBkcmFnZ2luZyA9IFRSVUUpKSU+JQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXIgPSAiQ2FydG9EQiIpJT4lCiAgc2V0VmlldyggbGF0PSA0MC43MTI3NDIsIGxuZz0tNzQuMDEzMzgyLCB6b29tID0gMTAgKSAlPiUKICBhZGRDaXJjbGVNYXJrZXJzKGxuZyA9IH5sb24sbGF0ID0gfmxhdCwgcmFkaXVzID0gMSwgY29sb3IgPSB+cGFsKGNsYXNzKSwgcG9wdXAgPSB+cGFzdGUwKCI8Yj4iLCJQcm9wZXJ0eSBUeXBlOiAiLCBjbGFzcywiPC9iPiIsIjxici8+IiwiRGF0ZTogIixzdHJfZXh0cmFjdChJTkNJREVOVF9EQVRFX1RJTUUsIHBhdHRlcm4gPSAiWzAtOV0rL1swLTldKy9bMC05XSsiKSwgIjxici8+IiwgIkFkZHJlc3M6ICIsIGFkZHJlc3MsICI8YnIvPiIsICJTcHJlYWQ6ICIsIHN0cl9zdWIoRklSRV9TUFJFQURfREVTQywgNSwtMSkpKSU+JQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IGMoIkFzc2VtYmx5IiwiRWR1Y2F0aW9uYWwiLCJIZWFsdGhjYXJlLCBEZXRlbnRpb24gYW5kIENvcnJlY3Rpb24iLCAiUmVzaWRlbnRpYWwiLCAiTWVyY2FudGlsZSBhbmQgQnVzaW5lc3MiLCAiRW5lcmd5IFByb2R1Y3Rpb24gUGxhbnQiLCAiTWFudWZhY3R1cmluZyBhbmQgUHJvY2Vzc2luZyIsICJTdG9yYWdlIiwgIk90aGVyIFByb3BlcnR5IiksIG9wYWNpdHkgPSAwLjgsIHRpdGxlID0gIlByb3BlcnR5IEFmZmVjdGVkIixwb3NpdGlvbiA9ICJ0b3BsZWZ0IikKCnByb3BlcnR5X21hcAojc2F2ZVdpZGdldChwcm9wZXJ0eV9tYXAsIGZpbGU9InByb3BlcnR5X21hcC5odG1sIikKYGBgCgojIyMjIyBiKSBDbHVzdGVyCgpBZGQgbWFya2VyIGNsdXN0ZXJpbmcsIHNvIHRoYXQgem9vbWluZyBpbiB3aWxsIHJldmVhbCB0aGUgaW5kaXZpZHVhbCBsb2NhdGlvbnMgYnV0IHRoZSB6b29tZWQgb3V0IG1hcCBvbmx5IHNob3dzIHRoZSBjbHVzdGVycy4gU2hvdyB0aGUgbWFwIHdpdGggY2x1c3RlcnMuCgpgYGB7cn0KY2x1c3Rlcl9wcm9wZXJ0eV9tYXAgPC0gbGVhZmxldChoaWdoZXN0X2FsYXJtLCBvcHRpb25zID0gbGVhZmxldE9wdGlvbnMobWluWm9vbSA9IDUsIGRyYWdnaW5nID0gVFJVRSkpJT4lCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlciA9ICJDYXJ0b0RCIiklPiUKICBzZXRWaWV3KCBsYXQ9IDQwLjcxMjc0MiwgbG5nPS03NC4wMTMzODIsIHpvb20gPSAxMCApICU+JQogIGFkZENpcmNsZU1hcmtlcnMobG5nID0gfmxvbixsYXQgPSB+bGF0LCByYWRpdXMgPSAxLCBjb2xvciA9IH5wYWwoY2xhc3MpLCBjbHVzdGVyT3B0aW9ucyA9IG1hcmtlckNsdXN0ZXJPcHRpb25zKCksIHBvcHVwID0gfnBhc3RlMCgiPGI+IiwiUHJvcGVydHkgVHlwZTogIiwgY2xhc3MsIjwvYj4iLCI8YnIvPiIsIkRhdGU6ICIsc3RyX2V4dHJhY3QoSU5DSURFTlRfREFURV9USU1FLCBwYXR0ZXJuID0gIlswLTldKy9bMC05XSsvWzAtOV0rIiksICI8YnIvPiIsICJBZGRyZXNzOiAiLCBhZGRyZXNzLCAiPGJyLz4iLCAiU3ByZWFkOiAiLCBzdHJfc3ViKEZJUkVfU1BSRUFEX0RFU0MsIDUsLTEpKSklPiUKICBhZGRMZWdlbmQocGFsID0gcGFsLCB2YWx1ZXMgPSBjKCJBc3NlbWJseSIsIkVkdWNhdGlvbmFsIiwiSGVhbHRoY2FyZSwgRGV0ZW50aW9uIGFuZCBDb3JyZWN0aW9uIiwgIlJlc2lkZW50aWFsIiwgIk1lcmNhbnRpbGUgYW5kIEJ1c2luZXNzIiwgIkVuZXJneSBQcm9kdWN0aW9uIFBsYW50IiwgIk1hbnVmYWN0dXJpbmcgYW5kIFByb2Nlc3NpbmciLCAiU3RvcmFnZSIsICJPdGhlciBQcm9wZXJ0eSIpLCBvcGFjaXR5ID0gMC44LCB0aXRsZSA9ICJQcm9wZXJ0eSBBZmZlY3RlZCIscG9zaXRpb24gPSAidG9wbGVmdCIpCgpjbHVzdGVyX3Byb3BlcnR5X21hcAojc2F2ZVdpZGdldChjbHVzdGVyX3Byb3BlcnR5X21hcCwgZmlsZT0iY2x1c3Rlcl9wcm9wZXJ0eV9tYXAuaHRtbCIpCmBgYAoKIyMjIyAzLiBGaXJlIEhvdXNlcwoKVGhlIHNlY29uZCBkYXRhIGZpbGUgY29udGFpbnMgdGhlIGxvY2F0aW9ucyBvZiB0aGUgMjE4IGZpcmVob3VzZXMgaW4gTmV3IFlvcmsgQ2l0eS4gU3RhcnQgd2l0aCB0aGUgbm9uLWNsdXN0ZXJlZCBtYXAgKDJiKSBhbmQgbm93IGFkanVzdCB0aGUgc2l6ZSBvZiB0aGUgY2lyY2xlIG1hcmtlcnMgYnkgc2V2ZXJpdHkgKGBUT1RBTF9JTkNJREVOVF9EVVJBVElPTmAgb3IgYFVOSVRTX09OU0NFTkVgIHNlZW0gcGxhdXNpYmxlIG9wdGlvbnMpLiBNb3JlIHNldmVyZSBpbmNpZGVudHMgc2hvdWxkIGhhdmUgbGFyZ2VyIGNpcmNsZXMgb24gdGhlIG1hcC4gT24gdGhlIG1hcCwgYWxzbyBhZGQgdGhlIGxvY2F0aW9ucyBvZiB0aGUgZmlyZSBob3VzZXMuIEFkZCB0d28gbGF5ZXJzICgiSW5jaWRlbnRzIiwgIkZpcmVob3VzZXMiKSB0aGF0IGFsbG93IHRoZSB1c2VyIHRvIHNlbGVjdCB3aGljaCBpbmZvcm1hdGlvbiB0byBzaG93LiAKYGBge3J9CiNoaWdoZXN0X2FsYXJtJFRPVEFMX0lOQ0lERU5UX0RVUkFUSU9OKQpzdW1tYXJ5KGhpZ2hlc3RfYWxhcm0kVE9UQUxfSU5DSURFTlRfRFVSQVRJT04pCmBgYAoKYGBge3J9CmluY2lkZW50c19maXJlaG91c2VfbWFwIDwtbGVhZmxldChoaWdoZXN0X2FsYXJtLCBvcHRpb25zID0gbGVhZmxldE9wdGlvbnMobWluWm9vbSA9IDUsIGRyYWdnaW5nID0gVFJVRSkpJT4lCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlciA9ICJDYXJ0b0RCIiklPiUKICBzZXRWaWV3KCBsYXQ9IDQwLjcxMjc0MiwgbG5nPS03NC4wMTMzODIsIHpvb20gPSAxMCApICU+JQogIGFkZENpcmNsZU1hcmtlcnMobG5nID0gfmxvbixsYXQgPSB+bGF0LCByYWRpdXMgPSB+VE9UQUxfSU5DSURFTlRfRFVSQVRJT04vNTAwMCAsIGNvbG9yID0gfnBhbChjbGFzcyksIHBvcHVwID0gfnBhc3RlMCgiPGI+IiwiUHJvcGVydHkgVHlwZTogIiwgY2xhc3MsIjwvYj4iLCI8YnIvPiIsIkRhdGU6ICIsc3RyX2V4dHJhY3QoSU5DSURFTlRfREFURV9USU1FLCBwYXR0ZXJuID0gIlswLTldKy9bMC05XSsvWzAtOV0rIiksICI8YnIvPiIsICJBZGRyZXNzOiAiLCBhZGRyZXNzLCAiPGJyLz4iLCAiU3ByZWFkOiAiLCBzdHJfc3ViKEZJUkVfU1BSRUFEX0RFU0MsIDUsLTEpKSwgZ3JvdXAgPSAiSW5jaWRlbnRzIiklPiUKICBhZGRMZWdlbmQocGFsID0gcGFsLCB2YWx1ZXMgPSBjKCJBc3NlbWJseSIsIkVkdWNhdGlvbmFsIiwiSGVhbHRoY2FyZSwgRGV0ZW50aW9uIGFuZCBDb3JyZWN0aW9uIiwgIlJlc2lkZW50aWFsIiwgIk1lcmNhbnRpbGUgYW5kIEJ1c2luZXNzIiwgIkVuZXJneSBQcm9kdWN0aW9uIFBsYW50IiwgIk1hbnVmYWN0dXJpbmcgYW5kIFByb2Nlc3NpbmciLCAiU3RvcmFnZSIsICJPdGhlciBQcm9wZXJ0eSIpLCBvcGFjaXR5ID0gMC44LCB0aXRsZSA9ICJQcm9wZXJ0eSBBZmZlY3RlZCIscG9zaXRpb24gPSAidG9wbGVmdCIpJT4lCiAgYWRkTWFya2VycyhkYXRhID0gZmlyZWhvdXNlcywgbG5nID0gfkxvbmdpdHVkZSwgbGF0ID0gfkxhdGl0dWRlLCBncm91cCA9ICJGaXJlaG91c2VzIiklPiUKICBhZGRMYXllcnNDb250cm9sKG92ZXJsYXlHcm91cHMgPSBjKCJJbmNpZGVudHMiLCAiRmlyZWhvdXNlcyIpKQppbmNpZGVudHNfZmlyZWhvdXNlX21hcAojc2F2ZVdpZGdldChpbmNpZGVudHNfZmlyZWhvdXNlX21hcCwgZmlsZT0iaW5jaWRlbnRzX2ZpcmVob3VzZV9tYXAuaHRtbCIpCmBgYAoKCiMjIyMgNC4gRGlzdGFuY2UgZnJvbSBGaXJlaG91c2UgYW5kIFJlc3BvbnNlIFRpbWUKCldlIG5vdyB3YW50IHRvIGludmVzdGlnYXRlIHdoZXRoZXIgdGhlIGRpc3RhbmNlIG9mIHRoZSBpbmNpZGVudCBmcm9tIHRoZSBuZWFyZXN0IGZpcmVob3VzZSB2YXJpZXMgYWNyb3NzIHRoZSBjaXR5LiAKCiMjIyMjIGEpIENhbGN1bGF0ZSBEaXN0YW5jZQoKRm9yIGFsbCBpbmNpZGVudCBsb2NhdGlvbnMgKGluZGVwZW5kZW50IG9mIHNldmVyaXR5KSwgaWRlbnRpZnkgdGhlIG5lYXJlc3QgZmlyZWhvdXNlIGFuZCBjYWxjdWxhdGUgdGhlIGRpc3RhbmNlIGJldHdlZW4gdGhlIGZpcmVob3VzZSBhbmQgdGhlIGluY2lkZW50IGxvY2F0aW9uLiBQcm92aWRlIGEgc2NhdHRlciBwbG90IHNob3dpbmcgdGhlIHRpbWUgdW50aWwgdGhlIGZpcnN0IGVuZ2luZSBhcnJpdmVkICh0aGUgdmFyaWFibGVzIGBJTkNJREVOVF9EQVRFX1RJTUVgICBhbmQgYEFSUklWQUxfREFURV9USU1FYCkgd2lsbCBiZSBoZWxwZnVsLiAKYGBge3J9CmxpYnJhcnkoc3ApCmxpYnJhcnkoc2YpCmxpYnJhcnkocmFzdGVyKQpsaWJyYXJ5KHJnZW9zKQojIHRyYW5zZm9ybSBmaXJlaG91c2UgaW50byBzZiBvYmplY3QKZmlyZWhvdXNlX3NmIDwtIHN0X2FzX3NmKGZpcmVob3VzZXMsIGNvb3JkcyA9IGMoIkxvbmdpdHVkZSIsICJMYXRpdHVkZSIpLCBjcnMgPSA0MzI2KQojIGJ1aWxkIGFuIGVtcHR5IGxpc3QgdG8gc3RvcmUgdGhlIG5lYXJlc3QgZGlzdGFuY2UKbmVhcmVzdCA8LWxpc3QoKQojIGl0ZXJhdGUgdGhlIGZpcmVfYnVpbGRpbmcgYW5kIHRyYW5zZm9ybSB0aGVtIGludG8gc3Agb2JqZWN0cyAKIyB1c2Ugc3RfZGlzdGFuY2UgdG8gY2FsY3VsYXRlIHRoZSBkaXN0YW5jZXMgYW5kIGZpbmQgdGhlIG5lYXJlc3QgZmlyZWhvdXNlCmZvcihpIGluIDE6bnJvdyhmaXJlX2J1aWxkaW5nKSl7CiAgcG9pbnRfc2YgPC0gc3RfYXNfc2YoZmlyZV9idWlsZGluZ1tpLF0sIGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwgY3JzID0gNDMyNikKICBuZWFyZXN0W2ldIDwtIG1pbihzdF9kaXN0YW5jZShwb2ludF9zZiwgZmlyZWhvdXNlX3NmKSkKfQpgYGAKCmBgYHtyfQpsZW5ndGgobmVhcmVzdCkKYW55KGlzLm5hKG5lYXJlc3QpKQojIGNyZWF0ZSBhIG5ldyBjb2x1bW4gaW4gZmlyZV9idWlsZGluZyBhYm91dCB0aGUgbmVhcmVzdCBkaXN0YW5jZSBmcm9tIGZpcmVob3VzZQpmaXJlX2J1aWxkaW5nWydkaXN0YW5jZSddIDwtIHVubGlzdChuZWFyZXN0KQpkaXN0YW5jZV9hbmRfdGltZSA8LSBmaXJlX2J1aWxkaW5nICU+JQogIGRwbHlyOjpzZWxlY3QoSU5DSURFTlRfREFURV9USU1FLCBBUlJJVkFMX0RBVEVfVElNRSwgUFJPUEVSVFlfVVNFX0RFU0MsSElHSEVTVF9MRVZFTF9ERVNDLEJPUk9VR0hfREVTQywgbG9uLCBsYXQsIGRpc3RhbmNlKQpoZWFkKGRpc3RhbmNlX2FuZF90aW1lKQpgYGAKYGBge3J9CmluY2lkZW50X3RpbWUgPC0gYXMuUE9TSVhjdChzdHJwdGltZShkaXN0YW5jZV9hbmRfdGltZVtbJ0lOQ0lERU5UX0RBVEVfVElNRSddXSwgZm9ybWF0ID0gIiVtLyVkLyVZICVIOiVNOiVTICVwIikpCmFycml2YWxfdGltZSA8LSBhcy5QT1NJWGN0KHN0cnB0aW1lKGRpc3RhbmNlX2FuZF90aW1lW1snQVJSSVZBTF9EQVRFX1RJTUUnXV0sIGZvcm1hdCA9ICIlbS8lZC8lWSAlSDolTTolUyAlcCIpKQp3YWl0aW5nX3RpbWUgPC0gYXJyaXZhbF90aW1lLWluY2lkZW50X3RpbWUKZGlzdGFuY2VfYW5kX3RpbWVbJ3dhaXRpbmdfdGltZV9zZWNzJ10gPC0gYXMubnVtZXJpYyh3YWl0aW5nX3RpbWUpCiNUaGVyZSBhcmUgc29tZSBtaXN0YWtlcyBpbiBvcmlnaW5hbCByZWNvcmRzIGxpa2Ugd3JvbmcgQU0vUE0KI1RyYW5zZnJvbSB0aG9zZSB3cm9uZyByZWNvcmRzIChuZWdhdGl2ZSBudW1iZXJzKSBieSBhZGRpbmcgMTIgaG91cnMgYmFjawpmb3IoaSBpbiAxOm5yb3coZGlzdGFuY2VfYW5kX3RpbWUpKXsKICBpZiAoIWlzLm5hKGRpc3RhbmNlX2FuZF90aW1lW2ksJ3dhaXRpbmdfdGltZV9zZWNzJ10pJmRpc3RhbmNlX2FuZF90aW1lW2ksJ3dhaXRpbmdfdGltZV9zZWNzJ10gPCAwKSB7CiAgICBkaXN0YW5jZV9hbmRfdGltZVtpLCd3YWl0aW5nX3RpbWVfc2VjcyddIDwtIGRpc3RhbmNlX2FuZF90aW1lW2ksJ3dhaXRpbmdfdGltZV9zZWNzJ10rMTIqNjAqNjAKICB9Cn0KaGVhZChkaXN0YW5jZV9hbmRfdGltZSkKYGBgCmBgYHtyfQpzdW1tYXJ5KGRpc3RhbmNlX2FuZF90aW1lKQpgYGAKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeShwbG90bHkpCmRmX3Bsb3QgPC1kaXN0YW5jZV9hbmRfdGltZSAlPiUKICBmaWx0ZXIoIWlzLm5hKHdhaXRpbmdfdGltZV9zZWNzKSklPiUKICBmaWx0ZXIoZGlzdGFuY2UgPCA1MDAwKSAlPiUKICBmaWx0ZXIod2FpdGluZ190aW1lX3NlY3MgPCA1MDAwKQpwIDwtZ2dwbG90KGRmX3Bsb3QsIGFlcyh4ID0gZGlzdGFuY2UsIHkgPSB3YWl0aW5nX3RpbWVfc2VjcykpKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpKwogIGxhYnMoeCA9ICJEaXN0YW5jZSBGcm9tIFRoZSBOZWFyZXN0IEZpcmVob3VzZSAobSkiLCB5ID0gIldhaXRpbmcgVGltZSBGb3IgVGhlIEZpcnN0IEVuZ2luZSAoc2VjcykiKSsKICB0aGVtZV9jbGVhbigpCnAKYGBgCk5vdyBhbHNvIHZpc3VhbGl6ZSB0aGUgcGF0dGVybnMgc2VwYXJhdGVseSBmb3Igc2V2ZXJlIGFuZCBub24tc2V2ZXJlIGluY2lkZW50cyAodXNlIGBISUdIRVNUX0xFVkVMX0RFU0NgIGJ1dCBmZWVsIGZyZWUgdG8gcmVkdWNlIHRoZSBudW1iZXIgb2YgY2F0ZWdvcmllcykuIFdoYXQgZG8geW91IGZpbmQ/CmBgYHtyfQpmaXJlX2xldmVscyA8LSBkaXN0YW5jZV9hbmRfdGltZSU+JQogIGZpbHRlcighaXMubmEoSElHSEVTVF9MRVZFTF9ERVNDKSkKZmlyZV9sZXZlbHNbJ2xldmVsJ109bGlzdChzdHJfc3ViKGZpcmVfbGV2ZWxzJEhJR0hFU1RfTEVWRUxfREVTQywxLDIpKQpmaXJlX2xldmVscyRsZXZlbFtmaXJlX2xldmVscyRsZXZlbCAlaW4lIGMoIjcgIiwgIjc1IildIDwtICJIaWdoIEFsYXJtIgpmaXJlX2xldmVscyRsZXZlbFtmaXJlX2xldmVscyRsZXZlbCAlaW4lIGMoIjUgIiwgIjU1IiwgIjQgIiwgIjQ0IiwgIjMgIiwgIjMzIildIDwtICJNZWRpdW0gQWxhcm0iCmZpcmVfbGV2ZWxzJGxldmVsW2ZpcmVfbGV2ZWxzJGxldmVsICVpbiUgYygiMiAiLCAiMjIiLCAiMTEiLCAiMCAiKV0gPC0gIkxvdyBBbGFybSIKZmlyZV9sZXZlbHMkbGV2ZWxbZmlyZV9sZXZlbHMkbGV2ZWwgJWluJSBjKCIxICIpXSA8LSAiVW5kZWZpbmVkIEFsYXJtIgpmaXJlX2xldmVscyRsZXZlbCA8LSBmYWN0b3IoZmlyZV9sZXZlbHMkbGV2ZWwsIGxldmVscz0gYygiTG93IEFsYXJtIiwiTWVkaXVtIEFsYXJtIiwiSGlnaCBBbGFybSIsIlVuZGVmaW5lZCBBbGFybSIpKQpgYGAKYGBge3J9CmZpcmVfbGV2ZWxzX3Bsb3QgPC0gZmlyZV9sZXZlbHMgJT4lCiAgZmlsdGVyKCFpcy5uYSh3YWl0aW5nX3RpbWVfc2VjcykpJT4lCiAgZmlsdGVyKGRpc3RhbmNlIDwgNTAwMCkgJT4lCiAgZmlsdGVyKHdhaXRpbmdfdGltZV9zZWNzIDwgMTAwMCkKZ2dwbG90KGZpcmVfbGV2ZWxzX3Bsb3QsIGFlcyh4PXdhaXRpbmdfdGltZV9zZWNzLCB5PWRpc3RhbmNlLCBjb2xvciA9IGxldmVsKSkrCiAgZ2VvbV9wb2ludChhbHBoYT0wLjQpKwogIGZhY2V0X2dyaWQofiBsZXZlbCkrCiAgbGFicyh4ID0gIldhaXRpbmcgVGltZSBGb3IgVGhlIEZpcnN0IEVuZ2luZSAoc2VjcykiLCB5ID0gIkRpc3RhbmNlIEZyb20gVGhlIE5lYXJlc3QgRmlyZWhvdXNlIChtKSIpKwogIHRoZW1lX2J3KCkKYGBgCiMjIyMjIGIpIE1hcCBvZiBSZXNwb25zZSBUaW1lcwoKUHJvdmlkZSBhIG1hcCB2aXN1YWxpemF0aW9uIG9mIHJlc3BvbnNlIHRpbWVzLiBJbnZlc3RpZ2F0ZSB3aGV0aGVyIHRoZSB0eXBlIG9mIHByb3BlcnR5IGFmZmVjdGVkIChgUFJPUEVSVFlfVVNFX0RFU0NgKSBvciBmaXJlIHNldmVyaXR5IChgSElHSEVTVF9MRVZFTF9ERVNDYCkgcGxheSBhIHJvbGUgaGVyZS4KCmBgYHtyfQpyZXNwb25zZV90aW1lIDwtIGZpcmVfbGV2ZWxzCnJlc3BvbnNlX3RpbWVbJ2NsYXNzJ109bGlzdChzdHJfc3ViKHJlc3BvbnNlX3RpbWUkUFJPUEVSVFlfVVNFX0RFU0MsMSwxKSkKCnJlc3BvbnNlX3RpbWUkY2xhc3NbcmVzcG9uc2VfdGltZSRjbGFzcyA9PSAiMSJdIDwtICJBc3NlbWJseSIKcmVzcG9uc2VfdGltZSRjbGFzc1tyZXNwb25zZV90aW1lJGNsYXNzID09ICIyIl0gPC0gIkVkdWNhdGlvbmFsIgpyZXNwb25zZV90aW1lJGNsYXNzW3Jlc3BvbnNlX3RpbWUkY2xhc3MgPT0gIjMiXSA8LSAiSGVhbHRoY2FyZSwgRGV0ZW50aW9uIGFuZCBDb3JyZWN0aW9uIgpyZXNwb25zZV90aW1lJGNsYXNzW3Jlc3BvbnNlX3RpbWUkY2xhc3MgPT0gIjQiXSA8LSAiUmVzaWRlbnRpYWwiCnJlc3BvbnNlX3RpbWUkY2xhc3NbcmVzcG9uc2VfdGltZSRjbGFzcyA9PSAiNSJdIDwtICJNZXJjYW50aWxlIGFuZCBCdXNpbmVzcyIKcmVzcG9uc2VfdGltZSRjbGFzc1tyZXNwb25zZV90aW1lJGNsYXNzID09ICI2Il0gPC0gIkVuZXJneSBQcm9kdWN0aW9uIFBsYW50IgpyZXNwb25zZV90aW1lJGNsYXNzW3Jlc3BvbnNlX3RpbWUkY2xhc3MgPT0gIjciXSA8LSAiTWFudWZhY3R1cmluZyBhbmQgUHJvY2Vzc2luZyIKcmVzcG9uc2VfdGltZSRjbGFzc1tyZXNwb25zZV90aW1lJGNsYXNzID09ICI4Il0gPC0gIlN0b3JhZ2UiCnJlc3BvbnNlX3RpbWUkY2xhc3NbcmVzcG9uc2VfdGltZSRjbGFzcyAlaW4lIGMoIjkiLCJVIiwiTiIsIjAiKV0gPC0gIk90aGVyIFByb3BlcnR5IgoKcmVzcG9uc2VfdGltZSRjbGFzcyA8LSBmYWN0b3IocmVzcG9uc2VfdGltZSRjbGFzcywgbGV2ZWxzPSBjKCJBc3NlbWJseSIsIkVkdWNhdGlvbmFsIiwiSGVhbHRoY2FyZSwgRGV0ZW50aW9uIGFuZCBDb3JyZWN0aW9uIiwgIlJlc2lkZW50aWFsIiwgIk1lcmNhbnRpbGUgYW5kIEJ1c2luZXNzIiwgIkVuZXJneSBQcm9kdWN0aW9uIFBsYW50IiwgIk1hbnVmYWN0dXJpbmcgYW5kIFByb2Nlc3NpbmciLCAiU3RvcmFnZSIsICJPdGhlciBQcm9wZXJ0eSIpKQpoZWFkKHJlc3BvbnNlX3RpbWUpCmBgYAoKYGBge3J9CmxvdyA8LSBmaWx0ZXIocmVzcG9uc2VfdGltZSwgbGV2ZWwgPT0gIkxvdyBBbGFybSIpCm1lZGl1bSA8LSBmaWx0ZXIocmVzcG9uc2VfdGltZSwgbGV2ZWwgPT0gIk1lZGl1bSBBbGFybSIpCmhpZ2ggPC0gZmlsdGVyKHJlc3BvbnNlX3RpbWUsIGxldmVsID09ICJIaWdoIEFsYXJtIikKYGBgCgpgYGB7cn0KcGFsX2xldmVsIDwtIGNvbG9yRmFjdG9yKHBhbGV0dGUgPSBjKCIjZjAzYjIwIiwgIiNmZWIyNGMiLCAiI2ZmZWRhMCIpLCAKICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkhpZ2ggQWxhcm0iLCJNZWRpdW0gQWxhcm0iLCJMb3cgQWxhcm0iKSkKYWxhcm1fbWFwIDwtIGxlYWZsZXQob3B0aW9ucyA9IGxlYWZsZXRPcHRpb25zKG1pblpvb20gPSA4LCBkcmFnZ2luZyA9IFRSVUUpKSAlPiUKICBhZGRQcm92aWRlclRpbGVzKCJDYXJ0b0RCLkRhcmtNYXR0ZXIiLG9wdGlvbnMgPSBwcm92aWRlclRpbGVPcHRpb25zKGF0dHJpYnV0aW9uID0gIiIpKSU+JQogIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IGxvdywgbG5nID0gfmxvbiwgbGF0ID0gfmxhdCwgcmFkaXVzID0gfndhaXRpbmdfdGltZV9zZWNzLzUwMDAsIGZpbGxPcGFjaXR5PTAuMywKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnBhbF9sZXZlbChsZXZlbCksICBncm91cCA9ICJMb3cgQWxhcm0iLCBwb3B1cD1+cGFzdGUoIkFsYXJtIExldmVsOiAiLGxldmVsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPlJlc3BvbnNlIFRpbWU6ICIsIHdhaXRpbmdfdGltZV9zZWNzLCIgc2Vjb25kcyIsICI8YnI+UHJvcGVydHkgVHlwZTogIiwgY2xhc3MpKSAlPiUgCiAgYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gbWVkaXVtLCBsbmcgPSB+bG9uLCBsYXQgPSB+bGF0LCByYWRpdXMgPSB+d2FpdGluZ190aW1lX3NlY3MvNTAwMCwgZmlsbE9wYWNpdHk9MC4zLAogICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+cGFsX2xldmVsKGxldmVsKSwgIGdyb3VwID0gIk1lZGl1bSBBbGFybSIsIHBvcHVwPX5wYXN0ZSgiQWxhcm0gTGV2ZWw6ICIsbGV2ZWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+UmVzcG9uc2UgVGltZTogIiwgd2FpdGluZ190aW1lX3NlY3MsICIgc2Vjb25kcyIsICI8YnI+UHJvcGVydHkgVHlwZTogIiwgY2xhc3MpKSAlPiUgIAogIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IGhpZ2gsIGxuZyA9IH5sb24sIGxhdCA9IH5sYXQsIHJhZGl1cyA9IH53YWl0aW5nX3RpbWVfc2Vjcy81MDAwLCBmaWxsT3BhY2l0eT0wLjMsCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5wYWxfbGV2ZWwobGV2ZWwpLCAgZ3JvdXAgPSAiSGlnaCBBbGFybSIsIHBvcHVwPX5wYXN0ZSgiQWxhcm0gTGV2ZWw6ICIsbGV2ZWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+UmVzcG9uc2UgVGltZTogIiwgd2FpdGluZ190aW1lX3NlY3MsICIgc2Vjb25kcyIsICI8YnI+UHJvcGVydHkgVHlwZTogIiwgY2xhc3MpKSAlPiUKICAgICAgICBzZXRWaWV3KGxhdD0gNDAuNzEyNzQyLCBsbmc9LTc0LjAxMzM4Miwgem9vbSA9IDEwKSAlPiUKICAgICAgICBhZGRMZWdlbmQocGFsID0gcGFsX2xldmVsLCB2YWx1ZXMgPSBjKCJIaWdoIEFsYXJtIiwiTWVkaXVtIEFsYXJtIiwgIkxvdyBBbGFybSIpLCBvcGFjaXR5ID0gMC43LCB0aXRsZSA9ICJBbGFybSBMZXZlbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gInRvcGxlZnQiKSU+JQogICAgICAgIGFkZExheWVyc0NvbnRyb2wob3ZlcmxheUdyb3VwcyA9IGMoIkhpZ2ggQWxhcm0iLCJNZWRpdW0gQWxhcm0iLCJMb3cgQWxhcm0iKSkKYWxhcm1fbWFwCiNzYXZlV2lkZ2V0KGFsYXJtX21hcCwgZmlsZT0iYWxhcm1fbWFwLmh0bWwiKQpgYGAKYGBge3J9CmxvbmdfcmVzcG9uc2UgPC0gc3Vic2V0KHJlc3BvbnNlX3RpbWUsIHdhaXRpbmdfdGltZV9zZWNzID4gNTAwKQpgYGAKCmBgYHtyfQpmaXJlSWNvbnMgPC0gaWNvbnMoCiAgaWNvblVybCA9ICJkYXRhL3JlZGZsYW1lLnBuZyIsCiAgaWNvbldpZHRoID0gMTUsIGljb25IZWlnaHQgPSAxNSwKICBpY29uQW5jaG9yWCA9IDcuNSwgaWNvbkFuY2hvclkgPSA4LjUKICApCmBgYAoKYGBge3J9CnBhbF9jbGFzcyA8LSBjb2xvckZhY3RvcihwYWxldHRlID0gIlRhYmxlYXUxMCIsIGxldmVscyA9IGMoIkFzc2VtYmx5IiwiRWR1Y2F0aW9uYWwiLCJIZWFsdGhjYXJlLCBEZXRlbnRpb24gYW5kIENvcnJlY3Rpb24iLCAiUmVzaWRlbnRpYWwiLCAiTWVyY2FudGlsZSBhbmQgQnVzaW5lc3MiLCAiRW5lcmd5IFByb2R1Y3Rpb24gUGxhbnQiLCAiTWFudWZhY3R1cmluZyBhbmQgUHJvY2Vzc2luZyIsICJTdG9yYWdlIiwgIk90aGVyIFByb3BlcnR5IikpCgpyZXNwb25zZV9yZXNpZGVudGlhbCA8LSBsZWFmbGV0KG9wdGlvbnMgPSBsZWFmbGV0T3B0aW9ucyhtaW5ab29tID0gNSwgZHJhZ2dpbmcgPSBUUlVFKSklPiUKYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlciA9ICJDYXJ0b0RCIikgJT4lCmFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IHJlc3BvbnNlX3RpbWUsIGxuZyA9IH5sb24sIGxhdCA9IH5sYXQsIHJhZGl1cyA9IH53YWl0aW5nX3RpbWVfc2Vjcy81MDAwLCBjb2xvciA9IH5wYWxfY2xhc3MoY2xhc3MpLCAKICAgICAgICAgICAgICAgICBmaWxsT3BhY2l0eT0wLjMsIHBvcHVwID0gfnBhc3RlKCJQcm9wZXJ0eSBUeXBlOiAiLCBjbGFzcywgIjxicj5SZXNwb25zZSBUaW1lOiAiLCB3YWl0aW5nX3RpbWVfc2VjcywiIHNlY29uZHMiKSklPiUKICBhZGRNYXJrZXJzKGRhdGE9IGxvbmdfcmVzcG9uc2UsaWNvbiA9IGZpcmVJY29ucywgCiAgICAgICAgICAgICBwb3B1cCA9IH5wYXN0ZSgiUHJvcGVydHkgVHlwZTogIiwgY2xhc3MsICI8YnI+UmVzcG9uc2UgVGltZTogIiwgd2FpdGluZ190aW1lX3NlY3MsIiBzZWNvbmRzIikpJT4lCiAgc2V0VmlldyggbGF0PSA0MC43MTI3NDIsIGxuZz0tNzQuMDEzMzgyLCB6b29tID0gMTAgKQpyZXNwb25zZV9yZXNpZGVudGlhbAojc2F2ZVdpZGdldChyZXNwb25zZV9yZXNpZGVudGlhbCwgZmlsZT0icmVzcG9uc2VfcmVzaWRlbnRpYWwuaHRtbCIpCmBgYApBY2NvcmRpbmcgdG8gdGhlIHBsb3QgYWJvdmUsIHRob3NlIGJpZyBjaXJjbGVzIGFuZCBmaXJlIGZsYW1lIGljb25zIGFyZSB0aGUgaW5jaWRlbnRzIHdpdGggYSBsb25nIHJlc3BvbnNlIHRpbWUuQ2xpY2tpbmcgdGhlIHBvcHVwLCB3ZSBjYW4gc2VlIG1vc3Qgb2YgdGhlbSBhcmUgcmVzaWRlbnRpYWwgcHJvcGVydGllcy4gVGhlbiB3ZSByZW1vdmUgdGhvc2UgIlJlc2lkZW50aWFsIiByZWNvcmRzIGFuZCBmaW5kIHNvbWUgaW5jaWRlbnRzIGhhcHBlbmVkIGluIGJ1c2luZXNzZXMgYW5kIGFzc2VtYmx5IGFsc28gaGFkIGEgbG9uZyByZXNwb25zZSB0aW1lLgpgYGB7cn0KZmlyZUljb25zMiA8LSBpY29ucygKICBpY29uVXJsID0gImRhdGEvZmxhbWUucG5nIiwKICBpY29uV2lkdGggPSAxNSwgaWNvbkhlaWdodCA9IDE1LAogIGljb25BbmNob3JYID0gNy41LCBpY29uQW5jaG9yWSA9IDguNQogICkKCnBhbF9wcm9wZXJ0eSA8LSBjb2xvckZhY3RvcihwYWxldHRlID0gIlNwZWN0cmFsIiwgbGV2ZWxzID0gYygiQXNzZW1ibHkiLCJFZHVjYXRpb25hbCIsIkhlYWx0aGNhcmUsIERldGVudGlvbiBhbmQgQ29ycmVjdGlvbiIsIk1lcmNhbnRpbGUgYW5kIEJ1c2luZXNzIiwgIkVuZXJneSBQcm9kdWN0aW9uIFBsYW50IiwgIk1hbnVmYWN0dXJpbmcgYW5kIFByb2Nlc3NpbmciLCAiU3RvcmFnZSIsICJPdGhlciBQcm9wZXJ0eSIpKQoKcmVzcG9uc2VfcHJvcGVydHlfbWFwIDwtIGxlYWZsZXQob3B0aW9ucyA9IGxlYWZsZXRPcHRpb25zKG1pblpvb20gPSA1LCBkcmFnZ2luZyA9IFRSVUUpKSU+JQphZGRQcm92aWRlclRpbGVzKCJFc3JpLldvcmxkSW1hZ2VyeSIsIG9wdGlvbnMgPSBwcm92aWRlclRpbGVPcHRpb25zKGF0dHJpYnV0aW9uID0gIiIpKSAlPiUKYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gc3Vic2V0KHJlc3BvbnNlX3RpbWUsIHJlc3BvbnNlX3RpbWUkY2xhc3MgIT0gIlJlc2lkZW50aWFsIiksIGxuZyA9IH5sb24sIGxhdCA9IH5sYXQsIHJhZGl1cyA9IH53YWl0aW5nX3RpbWVfc2Vjcy81MDAwLCBjb2xvciA9IH5wYWxfcHJvcGVydHkoY2xhc3MpLCBmaWxsT3BhY2l0eT0wLjcsIHBvcHVwID0gfnBhc3RlKCJQcm9wZXJ0eSBUeXBlOiAiLCBjbGFzcywgIjxicj5SZXNwb25zZSBUaW1lOiAiLCB3YWl0aW5nX3RpbWVfc2VjcywiIHNlY29uZHMiKSklPiUKICBhZGRNYXJrZXJzKGRhdGE9IHN1YnNldChsb25nX3Jlc3BvbnNlLCBsb25nX3Jlc3BvbnNlJGNsYXNzICE9ICJSZXNpZGVudGlhbCIpLGljb24gPSBmaXJlSWNvbnMyLCAKICAgICAgICAgICAgIHBvcHVwID0gfnBhc3RlKCJQcm9wZXJ0eSBUeXBlOiAiLCBjbGFzcywgIjxicj5SZXNwb25zZSBUaW1lOiAiLCB3YWl0aW5nX3RpbWVfc2VjcywiIHNlY29uZHMiKSklPiUKICBhZGRMZWdlbmQocGFsID0gcGFsX3Byb3BlcnR5LCB2YWx1ZXMgPSBjKCJBc3NlbWJseSIsIkVkdWNhdGlvbmFsIiwiSGVhbHRoY2FyZSwgRGV0ZW50aW9uIGFuZCBDb3JyZWN0aW9uIiwiTWVyY2FudGlsZSBhbmQgQnVzaW5lc3MiLCAiRW5lcmd5IFByb2R1Y3Rpb24gUGxhbnQiLCAiTWFudWZhY3R1cmluZyBhbmQgUHJvY2Vzc2luZyIsICJTdG9yYWdlIiwgIk90aGVyIFByb3BlcnR5IiksIG9wYWNpdHkgPSAwLjcsIHRpdGxlID0gIlByb3BlcnR5IEFmZmVjdGVkIixwb3NpdGlvbiA9ICJ0b3BsZWZ0IiklPiUKICBzZXRWaWV3KCBsYXQ9IDQwLjcxMjc0MiwgbG5nPS03NC4wMTMzODIsIHpvb20gPSAxMCApCnJlc3BvbnNlX3Byb3BlcnR5X21hcAojc2F2ZVdpZGdldChyZXNwb25zZV9wcm9wZXJ0eV9tYXAsIGZpbGU9InJlc3BvbnNlX3Byb3BlcnR5X21hcC5odG1sIikKYGBgClNob3cgYSBmYWNldGVkIGNob3JvcGxldGggbWFwIGluZGljYXRpbmcgaG93IHJlc3BvbnNlIHRpbWVzIGhhdmUgZGV2ZWxvcGVkIG92ZXIgdGhlIHllYXJzLiBXaGF0IGRvIHlvdSBmaW5kPwoKYGBge3J9CnJlc3BvbnNlX2Jvcm91Z2g8LWRpc3RhbmNlX2FuZF90aW1lICU+JQogIHNlbGVjdChJTkNJREVOVF9EQVRFX1RJTUUsQk9ST1VHSF9ERVNDLCB3YWl0aW5nX3RpbWVfc2VjcykKcmVzcG9uc2VfYm9yb3VnaFsnYm9yb3VnaCddID0gbGlzdChzdHJfc3ViKHJlc3BvbnNlX2Jvcm91Z2gkQk9ST1VHSF9ERVNDLDEsMSkpCnJlc3BvbnNlX2Jvcm91Z2gkYm9yb3VnaFtyZXNwb25zZV9ib3JvdWdoJGJvcm91Z2ggPT0gIjEiXSA8LSAiTWFuaGF0dGFuIgpyZXNwb25zZV9ib3JvdWdoJGJvcm91Z2hbcmVzcG9uc2VfYm9yb3VnaCRib3JvdWdoID09ICIyIl0gPC0gIkJyb254IgpyZXNwb25zZV9ib3JvdWdoJGJvcm91Z2hbcmVzcG9uc2VfYm9yb3VnaCRib3JvdWdoID09ICIzIl0gPC0gIlN0YXRlbiBJc2xhbmQiCnJlc3BvbnNlX2Jvcm91Z2gkYm9yb3VnaFtyZXNwb25zZV9ib3JvdWdoJGJvcm91Z2ggPT0gIjQiXSA8LSAiQnJvb2tseW4iCnJlc3BvbnNlX2Jvcm91Z2gkYm9yb3VnaFtyZXNwb25zZV9ib3JvdWdoJGJvcm91Z2ggPT0gIjUiXSA8LSAiUXVlZW5zIgpyZXNwb25zZV9ib3JvdWdoJGJvcm91Z2ggPC0gZmFjdG9yKHJlc3BvbnNlX2Jvcm91Z2gkYm9yb3VnaCwgbGV2ZWxzPSBjKCJNYW5oYXR0YW4iLCJCcm9ueCIsIlN0YXRlbiBJc2xhbmQiLCJCcm9va2x5biIsIlF1ZWVucyIpKQpyZXNwb25zZV9ib3JvdWdoWyd5ZWFyJ10gPSBsaXN0KHN0cl9zdWIocmVzcG9uc2VfYm9yb3VnaCRJTkNJREVOVF9EQVRFX1RJTUUsNywxMCkpCnJlc3BvbnNlX2Jvcm91Z2gkeWVhciA8LSBmYWN0b3IocmVzcG9uc2VfYm9yb3VnaCR5ZWFyLCBsZXZlbHM9IGMoIjIwMTMiLCIyMDE0IiwiMjAxNSIsIjIwMTYiLCIyMDE3IiwiMjAxOCIpKQpoZWFkKHJlc3BvbnNlX2Jvcm91Z2gpCmBgYApgYGB7cn0Kc3Vic2V0KHJlc3BvbnNlX2Jvcm91Z2gsIHJlc3BvbnNlX2Jvcm91Z2gkYm9yb3VnaCA9PSAiUXVlZW5zIiZyZXNwb25zZV9ib3JvdWdoJHllYXIgPT0iMjAxMyIpCmBgYApgYGB7cn0KYXZlcmFnZV9yZXNwb25zZV90aW1lIDwtcmVzcG9uc2VfYm9yb3VnaCAlPiUKICBmaWx0ZXIoIWlzLm5hKHdhaXRpbmdfdGltZV9zZWNzKSklPiUKICBncm91cF9ieShib3JvdWdoLCB5ZWFyKSAlPiUKICBzdW1tYXJpc2UobWVhbl9yZXNwb25zZV90aW1lID0gcm91bmQobWVhbih3YWl0aW5nX3RpbWVfc2VjcyksMikpCmF2ZXJhZ2VfcmVzcG9uc2VfdGltZQpgYGAKCmBgYHtyfQpsaWJyYXJ5KHJnZGFsKQpib3JvdWdoIDwtIHJlYWRPR1IoImRhdGEvYm9yb3VnaF9ib3VuZGFyaWVzLmdlb2pzb24iLCB2ZXJib3NlPUZBTFNFKQpib3JvdWdoQGRhdGEKYGBgCmBgYHtyfQpzaHBfcmVzcG9uc2UgPC0gYm9yb3VnaEBkYXRhICU+JQogIHJpZ2h0X2pvaW4oYXZlcmFnZV9yZXNwb25zZV90aW1lLCBieSA9IGMoImJvcm9fbmFtZSI9ICJib3JvdWdoIikpCnNocF9yZXNwb25zZQpgYGAKYGBge3J9CmJvcm91Z2hAZGF0YSA8LXNocF9yZXNwb25zZSAlPiUKICBmaWx0ZXIoeWVhciA9PSIyMDEzIikKc3VtbWFyeShib3JvdWdoJG1lYW5fcmVzcG9uc2VfdGltZSkKcGFsX3Jlc3BvbnNlIDwtIGNvbG9yTnVtZXJpYygiUHVPciIsIGRvbWFpbiA9IGJvcm91Z2gkbWVhbl9yZXNwb25zZV90aW1lKQptYXAyMDEzIDwtYm9yb3VnaCAlPiUKICBsZWFmbGV0KCklPiUKICBhZGRQcm92aWRlclRpbGVzKCJDYXJ0b0RCIiklPiUKICBhZGRQb2x5Z29ucyh3ZWlnaHQgPSAxLCBjb2xvciA9IH5wYWxfcmVzcG9uc2UobWVhbl9yZXNwb25zZV90aW1lKSwgZmlsbE9wYWNpdHkgPSAxLAogICAgICAgICAgICAgIGxhYmVsID0gfnBhc3RlMCgiTWVhbiBSZXNwb25zZSBUaW1lOiAiLCBtZWFuX3Jlc3BvbnNlX3RpbWUsICJzZWNvbmRzIiksCiAgICAgICAgICAgICAgaGlnaGxpZ2h0T3B0aW9ucyA9IGhpZ2hsaWdodE9wdGlvbnMod2VpZ2h0ID0gNSwgY29sb3IgPSAid2hpdGUiLCBicmluZ1RvRnJvbnQgPSBUUlVFKSklPiUKICBhZGRMZWdlbmQocGFsID0gcGFsX3Jlc3BvbnNlLCB2YWx1ZXMgPSB+IG1lYW5fcmVzcG9uc2VfdGltZSwgdGl0bGUgPSAiMjAxMyIsCiAgICAgICAgICAgIHBvc2l0aW9uID0gInRvcGxlZnQiLCBvcGFjaXR5PTAuNykKYGBgCmBgYHtyfQpib3JvdWdoQGRhdGEgPC1zaHBfcmVzcG9uc2UgJT4lCiAgZmlsdGVyKHllYXIgPT0iMjAxNCIpCnN1bW1hcnkoYm9yb3VnaCRtZWFuX3Jlc3BvbnNlX3RpbWUpCnBhbF9yZXNwb25zZSA8LSBjb2xvck51bWVyaWMoIlB1T3IiLCBkb21haW4gPSBib3JvdWdoJG1lYW5fcmVzcG9uc2VfdGltZSkKbWFwMjAxNCA8LWJvcm91Z2ggJT4lCiAgbGVhZmxldCgpJT4lCiAgYWRkUHJvdmlkZXJUaWxlcygiQ2FydG9EQiIpJT4lCiAgYWRkUG9seWdvbnMod2VpZ2h0ID0gMSwgY29sb3IgPSB+cGFsX3Jlc3BvbnNlKG1lYW5fcmVzcG9uc2VfdGltZSksIGZpbGxPcGFjaXR5ID0gMSwKICAgICAgICAgICAgICBsYWJlbCA9IH5wYXN0ZTAoIk1lYW4gUmVzcG9uc2UgVGltZTogIiwgbWVhbl9yZXNwb25zZV90aW1lLCAic2Vjb25kcyIpLAogICAgICAgICAgICAgIGhpZ2hsaWdodE9wdGlvbnMgPSBoaWdobGlnaHRPcHRpb25zKHdlaWdodCA9IDUsIGNvbG9yID0gIndoaXRlIiwgYnJpbmdUb0Zyb250ID0gVFJVRSkpJT4lCiAgYWRkTGVnZW5kKHBhbCA9IHBhbF9yZXNwb25zZSwgdmFsdWVzID0gfiBtZWFuX3Jlc3BvbnNlX3RpbWUsIHRpdGxlID0gIjIwMTQiLAogICAgICAgICAgICBwb3NpdGlvbiA9ICJ0b3BsZWZ0Iiwgb3BhY2l0eT0wLjcpCmBgYApgYGB7cn0KYm9yb3VnaEBkYXRhIDwtc2hwX3Jlc3BvbnNlICU+JQogIGZpbHRlcih5ZWFyID09IjIwMTUiKQpzdW1tYXJ5KGJvcm91Z2gkbWVhbl9yZXNwb25zZV90aW1lKQpwYWxfcmVzcG9uc2UgPC0gY29sb3JOdW1lcmljKCJQdU9yIiwgZG9tYWluID0gYm9yb3VnaCRtZWFuX3Jlc3BvbnNlX3RpbWUpCm1hcDIwMTUgPC1ib3JvdWdoICU+JQogIGxlYWZsZXQoKSU+JQogIGFkZFByb3ZpZGVyVGlsZXMoIkNhcnRvREIiKSU+JQogIGFkZFBvbHlnb25zKHdlaWdodCA9IDEsIGNvbG9yID0gfnBhbF9yZXNwb25zZShtZWFuX3Jlc3BvbnNlX3RpbWUpLCBmaWxsT3BhY2l0eSA9IDEsCiAgICAgICAgICAgICAgbGFiZWwgPSB+cGFzdGUwKCJNZWFuIFJlc3BvbnNlIFRpbWU6ICIsIG1lYW5fcmVzcG9uc2VfdGltZSwgInNlY29uZHMiKSwKICAgICAgICAgICAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyh3ZWlnaHQgPSA1LCBjb2xvciA9ICJ3aGl0ZSIsIGJyaW5nVG9Gcm9udCA9IFRSVUUpKSU+JQogIGFkZExlZ2VuZChwYWwgPSBwYWxfcmVzcG9uc2UsIHZhbHVlcyA9IH4gbWVhbl9yZXNwb25zZV90aW1lLCB0aXRsZSA9ICIyMDEzIiwKICAgICAgICAgICAgcG9zaXRpb24gPSAidG9wbGVmdCIsIG9wYWNpdHk9MC43KQpgYGAKYGBge3J9CmJvcm91Z2hAZGF0YSA8LXNocF9yZXNwb25zZSAlPiUKICBmaWx0ZXIoeWVhciA9PSIyMDE2IikKc3VtbWFyeShib3JvdWdoJG1lYW5fcmVzcG9uc2VfdGltZSkKcGFsX3Jlc3BvbnNlIDwtIGNvbG9yTnVtZXJpYygiUHVPciIsIGRvbWFpbiA9IGJvcm91Z2gkbWVhbl9yZXNwb25zZV90aW1lKQptYXAyMDE2IDwtYm9yb3VnaCAlPiUKICBsZWFmbGV0KCklPiUKICBhZGRQcm92aWRlclRpbGVzKCJDYXJ0b0RCIiklPiUKICBhZGRQb2x5Z29ucyh3ZWlnaHQgPSAxLCBjb2xvciA9IH5wYWxfcmVzcG9uc2UobWVhbl9yZXNwb25zZV90aW1lKSwgZmlsbE9wYWNpdHkgPSAxLAogICAgICAgICAgICAgIGxhYmVsID0gfnBhc3RlMCgiTWVhbiBSZXNwb25zZSBUaW1lOiAiLCBtZWFuX3Jlc3BvbnNlX3RpbWUsICJzZWNvbmRzIiksCiAgICAgICAgICAgICAgaGlnaGxpZ2h0T3B0aW9ucyA9IGhpZ2hsaWdodE9wdGlvbnMod2VpZ2h0ID0gNSwgY29sb3IgPSAid2hpdGUiLCBicmluZ1RvRnJvbnQgPSBUUlVFKSklPiUKICBhZGRMZWdlbmQocGFsID0gcGFsX3Jlc3BvbnNlLCB2YWx1ZXMgPSB+IG1lYW5fcmVzcG9uc2VfdGltZSwgdGl0bGUgPSAiMjAxNiIsCiAgICAgICAgICAgIHBvc2l0aW9uID0gInRvcGxlZnQiLCBvcGFjaXR5PTAuNykKYGBgCmBgYHtyfQpib3JvdWdoQGRhdGEgPC1zaHBfcmVzcG9uc2UgJT4lCiAgZmlsdGVyKHllYXIgPT0iMjAxNyIpCnN1bW1hcnkoYm9yb3VnaCRtZWFuX3Jlc3BvbnNlX3RpbWUpCnBhbF9yZXNwb25zZSA8LSBjb2xvck51bWVyaWMoIlB1T3IiLCBkb21haW4gPSBib3JvdWdoJG1lYW5fcmVzcG9uc2VfdGltZSkKbWFwMjAxNyA8LWJvcm91Z2ggJT4lCiAgbGVhZmxldCgpJT4lCiAgYWRkUHJvdmlkZXJUaWxlcygiQ2FydG9EQiIpJT4lCiAgYWRkUG9seWdvbnMod2VpZ2h0ID0gMSwgY29sb3IgPSB+cGFsX3Jlc3BvbnNlKG1lYW5fcmVzcG9uc2VfdGltZSksIGZpbGxPcGFjaXR5ID0gMSwKICAgICAgICAgICAgICBsYWJlbCA9IH5wYXN0ZTAoIk1lYW4gUmVzcG9uc2UgVGltZTogIiwgbWVhbl9yZXNwb25zZV90aW1lLCAic2Vjb25kcyIpLAogICAgICAgICAgICAgIGhpZ2hsaWdodE9wdGlvbnMgPSBoaWdobGlnaHRPcHRpb25zKHdlaWdodCA9IDUsIGNvbG9yID0gIndoaXRlIiwgYnJpbmdUb0Zyb250ID0gVFJVRSkpJT4lCiAgYWRkTGVnZW5kKHBhbCA9IHBhbF9yZXNwb25zZSwgdmFsdWVzID0gfiBtZWFuX3Jlc3BvbnNlX3RpbWUsIHRpdGxlID0gIjIwMTciLAogICAgICAgICAgICBwb3NpdGlvbiA9ICJ0b3BsZWZ0Iiwgb3BhY2l0eT0wLjcpCmBgYApgYGB7cn0KYm9yb3VnaEBkYXRhIDwtc2hwX3Jlc3BvbnNlICU+JQogIGZpbHRlcih5ZWFyID09IjIwMTgiKQpzdW1tYXJ5KGJvcm91Z2gkbWVhbl9yZXNwb25zZV90aW1lKQpwYWxfcmVzcG9uc2UgPC0gY29sb3JOdW1lcmljKCJQdU9yIiwgZG9tYWluID0gYm9yb3VnaCRtZWFuX3Jlc3BvbnNlX3RpbWUpCm1hcDIwMTggPC1ib3JvdWdoICU+JQogIGxlYWZsZXQoKSU+JQogIGFkZFByb3ZpZGVyVGlsZXMoIkNhcnRvREIiKSU+JQogIGFkZFBvbHlnb25zKHdlaWdodCA9IDEsIGNvbG9yID0gfnBhbF9yZXNwb25zZShtZWFuX3Jlc3BvbnNlX3RpbWUpLCBmaWxsT3BhY2l0eSA9IDEsCiAgICAgICAgICAgICAgbGFiZWwgPSB+cGFzdGUwKCJNZWFuIFJlc3BvbnNlIFRpbWU6ICIsIG1lYW5fcmVzcG9uc2VfdGltZSwgInNlY29uZHMiKSwKICAgICAgICAgICAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyh3ZWlnaHQgPSA1LCBjb2xvciA9ICJ3aGl0ZSIsIGJyaW5nVG9Gcm9udCA9IFRSVUUpKSU+JQogIGFkZExlZ2VuZChwYWwgPSBwYWxfcmVzcG9uc2UsIHZhbHVlcyA9IH4gbWVhbl9yZXNwb25zZV90aW1lLCB0aXRsZSA9ICIyMDE4IiwKICAgICAgICAgICAgcG9zaXRpb24gPSAidG9wbGVmdCIsIG9wYWNpdHk9MC43KQpgYGAKYGBge3J9CmxpYnJhcnkobWFwdmlldykKZmFjZXRfbWFwIDwtIHN5bmMobWFwMjAxMywgbWFwMjAxNCwgbWFwMjAxNSwgbWFwMjAxNiwgbWFwMjAxNyxtYXAyMDE4LCBuY29sID0gMywgc3luYyA9ICJhbGwiKQpmYWNldF9tYXAKYGBgCgojIyBTdWJtaXNzaW9uCgpQbGVhc2UgZm9sbG93IHRoZSBbaW5zdHJ1Y3Rpb25zXSgvRXhlcmNpc2VzL2hvbWV3b3JrX3N1Ym1pc3Npb25faW5zdHJ1Y3Rpb25zLm1kKSB0byBzdWJtaXQgeW91ciBob21ld29yay4gVGhlIGhvbWV3b3JrIGlzIGR1ZSBvbiBXZWRuZXNkYXksIE1hcmNoIDI1LgoKIyMgUGxlYXNlIHN0YXkgaG9uZXN0IQoKSWYgeW91IGRvIGNvbWUgYWNyb3NzIHNvbWV0aGluZyBvbmxpbmUgdGhhdCBwcm92aWRlcyBwYXJ0IG9mIHRoZSBhbmFseXNpcyAvIGNvZGUgZXRjLiwgcGxlYXNlIG5vIHdob2xlc2FsZSBjb3B5aW5nIG9mIG90aGVyIGlkZWFzLiBXZSBhcmUgdHJ5aW5nIHRvIGV2YWx1YXRlIHlvdXIgYWJpbGl0aWVzIHRvIHZpc3VhbGl6ZSBkYXRhLCBub3QgdGhlIGFiaWxpdHkgdG8gZG8gaW50ZXJuZXQgc2VhcmNoZXMuIEFsc28sIHRoaXMgaXMgYW4gaW5kaXZpZHVhbGx5IGFzc2lnbmVkIGV4ZXJjaXNlIC0tIHBsZWFzZSBrZWVwIHlvdXIgc29sdXRpb24gdG8geW91cnNlbGYuCg==